# Network Decode with Modal Operator

I am working on a script that reads network packets to modify the emission strength of lights. In order to use the UI at the same time as reading from the network, I have created a modal operator:

class BlenDMX(bpy.types.Operator):
bl_idname = ".blendmx"
bl_label = "BlenDMX"
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
_updating = False
_timer = None

def modal(self, context, event):
if event.type == 'TIMER' and not self._updating:
self._updating = True
#Here is where i would read the data from the network and modify the lights.
#I will spare you those details for now...
self._updating = False
return {'PASS_THROUGH'}

def execute(self, context):
self._updating = False
self._timer = context.window_manager.event_timer_add(0.5, context.window)
port = 6454
self.s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.s.bind(("127.0.0.1", port))
return {'RUNNING_MODAL'}

def cancel(self, context):
context.window_manager.event_timer_remove(self._timer)
self._timer = None
return {'CANCELLED'}

def register():
bpy.utils.register_class(BlenDMX)

def unregister():
bpy.utils.unregister_class(BlenDMX)

if __name__=="__main__":
register()


Unfortunately, 0.5 seconds is too slow for proper processing of these packets, but something like 0.1 will lock up the UI, defeating the purpose of the modal operator in the first place.

My thought is to check to see if an adjacent group of network packets are identical, which would mean my data stream has temporarily "settled." I can work out the logic for that but am unsure how to use it to make the modal operator release control back to the UI. I would also need to then check for when data becomes "unsettled" so I know to run the decodes in rapid succession again, allowing the UI to temporarily lock up.

Again, I can work out the logic for scanning adjacent packets, but I am unsure of where to put that code and what to call to implement this variable decode speed. Your help is appreciated!

Here is perhaps how I would try to implement it (please excuse me if this is too simplistic):

• Maintain a queue of the packets that allows concurrent access
• One thread (process A) continually monitors the queue and processes and removes the packets from it. Since this does not have any timer even, it isn't subject to time constraint; it will have to wait until there are packets available in the queue (maybe feasible with multiprocessing python package)
• The timer driven modal function (process B) can simply fetch the network packets and place them in the queue, this can be (I guess) reasonably expected to finish in less than 0.1 sec
• I am not sure whether the 'settled' and 'unsettled' distinction for the state of the incoming flow will be of much use in this case, as this information will always be a posteriori (but again I maybe totally wrong).

NB: You may also want to put this question on stackoverflow, since this is more of a algorithm/python question.

• Thanks for the suggestion! I definitely wanted to deploy multithreading in this application, but was advised not to use threads in Blender. I am going to play with this idea of yours regardless and will get back to you on how it goes. Will crosspost to the main stackoverflow. – akclucc Oct 20 '18 at 12:52

Super simple fix here! My light updating code already has a detection method for identical data packets, so all I had to do was re-define the modal's timer to go into "decode mode" when two packets are identical:

#if two packets are identical (UI Mode):
context.window_manager.event_timer_remove(self._timer)
self._timer = context.window_manager.event_timer_add(0.5, context.window)
#otherwise (Decode Mode):
context.window_manager.event_timer_remove(self._timer)
self._timer = context.window_manager.event_timer_add(0.001, context.window)