diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..0d20b6487c61e7d1bde93acf4a14b7a89083a16d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+*.pyc
diff --git a/npyscreenreactor.py b/npyscreenreactor.py
new file mode 100644
index 0000000000000000000000000000000000000000..b7931cd06ca502b3fb67114f82d1ff00564eed7d
--- /dev/null
+++ b/npyscreenreactor.py
@@ -0,0 +1,99 @@
+#!/usr/bin/env python
+
+# npyscreenreactory.py
+
+# Inspired by pausingreactor.py and xmmsreactor.py
+
+# npyscreen modifications
+# Copyright (c) 2015 Mark Tearle <mark@tearle.com>
+
+"""
+This module provides wxPython event loop support for Twisted.
+
+In order to use this support, simply do the following::
+
+    |  import npyscreenreactor
+    |  npyscreenreactor.install()
+
+Then, when your root npyscreenApp has been created::
+
+    | from twisted.internet import reactor
+    | reactor.registerNpyscreenApp(yourApp)
+    | reactor.run()
+
+Then use twisted.internet APIs as usual. Stop the event loop using
+reactor.stop(), not yourApp.ExitMainLoop().
+
+IMPORTANT: tests will fail when run under this reactor. This is
+expected and probably does not reflect on the reactor's ability to run
+real applications.
+
+Maintainer: Mark Tearle
+"""
+
+import sys
+
+import Queue
+
+from twisted.python import log, runtime
+#from twisted.internet import _threadedselect
+from twisted.internet import selectreactor
+
+import npyscreen
+
+#class NpyscreenReactor(_threadedselect.ThreadedSelectReactor):
+class NpyscreenReactor(selectreactor.SelectReactor):
+    """
+    npyscreen reactor.
+
+    npyscreen drives the event loop
+    """
+    def doIteration(self, timeout):
+	selectreactor.SelectReactor.doIteration(self, timeout)
+
+	# push event back on npyscreen queue
+	self.npyscreenapp.queue_event(npyscreen.Event("_NPYSCREEN_REACTOR"))
+
+    def registerNpyscreenApp(self, npyscreenapp):
+        """
+        Register npyscreen.StandardApp instance with the reactor.
+        """
+        self.npyscreenapp = npyscreenapp
+	self.npyscreenapp.add_event_hander("_NPYSCREEN_REACTOR", self._twisted_events)
+
+    def _twisted_events(self, event):
+	self.doIteration(0)
+
+    def _stopNpyscreen(self):
+        """
+        Stop the Npsycreen event loop if it hasn't already been stopped.
+
+        Called during Twisted event loop shutdown.
+        """
+        if hasattr(self, "npyscreenapp"):
+            self.npyscreenapp.setNextForm(None)
+
+    def run(self):
+        """
+        Start the reactor.
+        """
+        # add cleanup events:
+        self.addSystemEventTrigger("after", "shutdown", self._stopNpyscreen)
+
+	# put event on queue to do twisted things 
+	self.npyscreenapp.queue_event(npyscreen.Event("_NPYSCREEN_REACTOR"))
+
+	#
+        self.npyscreenapp.run()
+
+def install():
+    """
+    Configure the twisted mainloop to be run inside the npyscreen mainloop.
+    """
+    reactor = NpyscreenReactor()
+    from twisted.internet.main import installReactor
+    installReactor(reactor)
+    return reactor
+
+
+__all__ = ['install']
diff --git a/virtualcoke.py b/virtualcoke.py
index e680019c3711ed909b6de5e2b16c397316b39ed1..0de90e80f0dbaa326b677f3328fd5baa251014c5 100755
--- a/virtualcoke.py
+++ b/virtualcoke.py
@@ -2,13 +2,20 @@
 import npyscreen
 from datetime import datetime
 
+# npyscreen twisted reactor
+import npyscreenreactor
+reactor = npyscreenreactor.install()
+
 # Incorporates code from
 #Pymodbus Asynchronous Server Example
 
 #---------------------------------------------------------------------------# 
 # import the various server implementations
 #---------------------------------------------------------------------------# 
-from pymodbus.server.async import StartTcpServer
+from pymodbus.constants import Defaults
+from pymodbus.transaction import ModbusSocketFramer, ModbusAsciiFramer
+from pymodbus.server.async import ModbusServerFactory
+
 
 from pymodbus.datastore import ModbusSequentialDataBlock, ModbusSparseDataBlock
 from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext
@@ -31,6 +38,28 @@ logging.basicConfig()
 log = logging.getLogger()
 log.setLevel(logging.DEBUG)
 
+# Factory for modbus
+
+def StartModbusAsyncServer(context, identity=None, address=None, console=False):
+    ''' Helper method to start the Modbus Async TCP server
+
+    :param context: The server data context
+    :param identify: The server identity to use (default empty)
+    :param address: An optional (interface, port) to bind to.
+    :param console: A flag indicating if you want the debug console
+    '''
+    from twisted.internet import reactor
+
+    address = address or ("", Defaults.Port)
+    framer  = ModbusSocketFramer
+    factory = ModbusServerFactory(context, framer, identity)
+    if console: InstallManagementConsole({'factory': factory})
+
+    log.info("Starting Modbus TCP Server on %s:%s" % address)
+    reactor.listenTCP(address[1], factory, interface=address[0])
+
+
+#
 
 class ContainedMultiSelect(npyscreen.BoxTitle):
     _contained_widget = npyscreen.TitleMultiSelect
@@ -148,7 +177,7 @@ class VirtualCoke(npyscreen.Form):
         self.editing = False
 
 
-class VirtualCokeApp(npyscreen.NPSAppManaged):
+class VirtualCokeApp(npyscreen.StandardApp):
     keypress_timeout_default = 1
 
     def onStart(self):
@@ -200,100 +229,99 @@ class VirtualCokeApp(npyscreen.NPSAppManaged):
     # Coke Emulator code below
 
 
-if __name__ == "__main__":
-    App = VirtualCokeApp()
-    App.run()
-
-
-##---------------------------------------------------------------------------# 
-## initialize your data store
-##---------------------------------------------------------------------------# 
-## The datastores only respond to the addresses that they are initialized to.
-## Therefore, if you initialize a DataBlock to addresses of 0x00 to 0xFF, a
-## request to 0x100 will respond with an invalid address exception. This is
-## because many devices exhibit this kind of behavior (but not all)::
-##
-##     block = ModbusSequentialDataBlock(0x00, [0]*0xff)
-##
-## Continuting, you can choose to use a sequential or a sparse DataBlock in
-## your data context.  The difference is that the sequential has no gaps in
-## the data while the sparse can. Once again, there are devices that exhibit
-## both forms of behavior::
-##
-##     block = ModbusSparseDataBlock({0x00: 0, 0x05: 1})
-##     block = ModbusSequentialDataBlock(0x00, [0]*5)
-##
-## Alternately, you can use the factory methods to initialize the DataBlocks
-## or simply do not pass them to have them initialized to 0x00 on the full
-## address range::
-##
-##     store = ModbusSlaveContext(di = ModbusSequentialDataBlock.create())
-##     store = ModbusSlaveContext()
-##
-## Finally, you are allowed to use the same DataBlock reference for every
-## table or you you may use a seperate DataBlock for each table. This depends
-## if you would like functions to be able to access and modify the same data
-## or not::
-##
-##     block = ModbusSequentialDataBlock(0x00, [0]*0xff)
-##     store = ModbusSlaveContext(di=block, co=block, hr=block, ir=block)
-##---------------------------------------------------------------------------# 
-#
-##---------------------------------------------------------------------------# 
-## create your custom data block with callbacks
-##---------------------------------------------------------------------------# 
-#class CallbackDataBlock(ModbusSparseDataBlock):
-#    ''' A datablock that stores the new value in memory
-#    and passes the operation to a message queue for further
-#    processing.
-#    '''
-#
-#    def __init__(self, values):
-#	self.toggle = 1
-#	super(CallbackDataBlock, self).__init__(values)
-#
-#
-#    def getValues(self, address, count=1):
-#        ''' Returns the requested values from the datastore
-#
-#        :param address: The starting address
-#        :param count: The number of values to retrieve
-#        :returns: The requested values from a:a+c
-#        '''	
-#	log.debug("CBD getValues %d:%d" % (address, count))
-#
-#	if address < 1024:
-#		return [1]
+#---------------------------------------------------------------------------# 
+# initialize your data store
+#---------------------------------------------------------------------------# 
+# The datastores only respond to the addresses that they are initialized to.
+# Therefore, if you initialize a DataBlock to addresses of 0x00 to 0xFF, a
+# request to 0x100 will respond with an invalid address exception. This is
+# because many devices exhibit this kind of behavior (but not all)::
 #
-#	self.toggle = self.toggle+1
+#     block = ModbusSequentialDataBlock(0x00, [0]*0xff)
 #
-#	log.debug("CBD getValues toggle %d" % (self.toggle))
-#	if self.toggle % 3 == 0:
-#		return [1]
-#	
-#	if self.toggle % 3 == 1:
-#		return [1]
+# Continuting, you can choose to use a sequential or a sparse DataBlock in
+# your data context.  The difference is that the sequential has no gaps in
+# the data while the sparse can. Once again, there are devices that exhibit
+# both forms of behavior::
 #
-#	if self.toggle % 3 == 2:
-#		return [0]
-#	
+#     block = ModbusSparseDataBlock({0x00: 0, 0x05: 1})
+#     block = ModbusSequentialDataBlock(0x00, [0]*5)
 #
-#	return [1]
-#	
+# Alternately, you can use the factory methods to initialize the DataBlocks
+# or simply do not pass them to have them initialized to 0x00 on the full
+# address range::
 #
+#     store = ModbusSlaveContext(di = ModbusSequentialDataBlock.create())
+#     store = ModbusSlaveContext()
 #
-#store = ModbusSlaveContext(
-#    #di = ModbusSequentialDataBlock(0, [17]*100),
-#    #co = ModbusSequentialDataBlock(0, [17]*100),
-#    #hr = ModbusSequentialDataBlock(0, [17]*100),
-#    #ir = ModbusSequentialDataBlock(0, [17]*100))
-#    di = CallbackDataBlock([0]*100),
-#    co = CallbackDataBlock([0]*65536),
-#    hr = CallbackDataBlock([0]*100),
-#    ir = CallbackDataBlock([0]*100))
-#context = ModbusServerContext(slaves=store, single=True)
+# Finally, you are allowed to use the same DataBlock reference for every
+# table or you you may use a seperate DataBlock for each table. This depends
+# if you would like functions to be able to access and modify the same data
+# or not::
 #
-##---------------------------------------------------------------------------# 
-## run the server you want
-##---------------------------------------------------------------------------# 
-#StartTcpServer(context)
+#     block = ModbusSequentialDataBlock(0x00, [0]*0xff)
+#     store = ModbusSlaveContext(di=block, co=block, hr=block, ir=block)
+#---------------------------------------------------------------------------# 
+
+#---------------------------------------------------------------------------# 
+# create your custom data block with callbacks
+#---------------------------------------------------------------------------# 
+class CallbackDataBlock(ModbusSparseDataBlock):
+    ''' A datablock that stores the new value in memory
+    and passes the operation to a message queue for further
+    processing.
+    '''
+
+    def __init__(self, values):
+	self.toggle = 1
+	super(CallbackDataBlock, self).__init__(values)
+
+
+    def getValues(self, address, count=1):
+        ''' Returns the requested values from the datastore
+
+        :param address: The starting address
+        :param count: The number of values to retrieve
+        :returns: The requested values from a:a+c
+        '''	
+	log.debug("CBD getValues %d:%d" % (address, count))
+
+	if address < 1024:
+		return [1]
+
+	self.toggle = self.toggle+1
+
+	log.debug("CBD getValues toggle %d" % (self.toggle))
+	if self.toggle % 3 == 0:
+		return [1]
+	
+	if self.toggle % 3 == 1:
+		return [1]
+
+	if self.toggle % 3 == 2:
+		return [0]
+	
+
+	return [1]
+	
+
+
+store = ModbusSlaveContext(
+    #di = ModbusSequentialDataBlock(0, [17]*100),
+    #co = ModbusSequentialDataBlock(0, [17]*100),
+    #hr = ModbusSequentialDataBlock(0, [17]*100),
+    #ir = ModbusSequentialDataBlock(0, [17]*100))
+    di = CallbackDataBlock([0]*100),
+    co = CallbackDataBlock([0]*65536),
+    hr = CallbackDataBlock([0]*100),
+    ir = CallbackDataBlock([0]*100))
+
+context = ModbusServerContext(slaves=store, single=True)
+
+
+if __name__ == "__main__":
+    App = VirtualCokeApp()
+    reactor.registerNpyscreenApp(App)
+    StartModbusAsyncServer(context)
+    reactor.run()
+