How to pass a created (win32COM) object into a Dash live-update callback?

I’ve been stuck on this for a long time. My code is in 2 parts. Below is the code I use to create my object (an electronic instrument connected to my laptop via USB that collects data):

# vna_control.py

# It is better to create a class of VNA object that contains a bunch of methods.
from pathlib import Path
import numpy as np
import win32com.client

calibrationpath = Path("C:/Users/ayilarana/PycharmProjects/pythonProject/ring.cal")
calibrationkitpath = Path("C:/Users/ayilarana/PycharmProjects/pythonProject/SF287.kit")

class VNA_Object:
    def __init__(self, name, description):
        self.vna = win32com.client.Dispatch("PicoControl2.PicoVNA_2")
        self.name = name
        self.type = description

    def open_vna(self):

        findVNA = self.vna.FND()
        if findVNA == 0:
            print("No VNA Loaded")
            exit()
        else:
            print('VNA ' + str(findVNA) + ' Loaded')

        dll = self.vna.DLLVer()
        print(dll)

        cali = self.vna.SelectKit(calibrationkitpath, "1")
        print("Result " + str(cali))

        enhance_averages = self.vna.SetEnhance("aver", 100)
        print("Averages: " + enhance_averages)

        ans = self.vna.SelectCal(calibrationpath)
        print("Result " + str(ans))

        return print("VNA Open")

    def measure_vna_frequency(self):
        meas = self.vna.Measure("S11")
        print("Result " + str(meas))
        raw = self.vna.GetData("S11", "logmag", 0)
        splitdata = raw.split(',')
        converteddata = np.array(splitdata)
        converteddata = converteddata.astype(np.float)
        x_frequency = converteddata[:: 2]
        return x_frequency

    def measure_vna_ys11(self):
        meas = self.vna.Measure("S11")
        print("Result " + str(meas))
        raw = self.vna.GetData("S11", "logmag", 0)
        splitdata = raw.split(',')
        converteddata = np.array(splitdata)
        converteddata = converteddata.astype(np.float)
        y_s11 = converteddata[1:: 2]
        return y_s11

    def close_vna(self):
        self.vna.CloseVNA()
        return print("VNA Closed")

Below is my MAIN code to control my instrument and plot the data (hopefully every 1s) onto a Dash app:

# basic4.py
# import stuff for paths and serials
import win32com.client
import threading
import pythoncom
from pathlib import Path

import vna_control as vna

import time

# import stuff for treating data
import panda_express as pe
import datetime
import numpy as np

# import stuff for plotly and dash
import dash
from dash.dependencies import Output, Input
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objs as go

def start():
    # Initialize
    pythoncom.CoInitialize()

    # Get instance
    picoVNACOMObj = vna.VNA_Object("Pico VNA", "VNA Instrument")

    picoVNACOMObj.open_vna()
    print(picoVNACOMObj.measure_vna_frequency())
    print(picoVNACOMObj.measure_vna_ys11())

    # Create id
    global picoVNACOMObj_id
    picoVNACOMObj_id = pythoncom.CoMarshalInterThreadInterfaceInStream(pythoncom.IID_IDispatch, picoVNACOMObj)

    # Pass the id to the new thread
    thread = threading.Thread(target=update_graph_scatter, kwargs={'picoVNACOMObj_id': picoVNACOMObj_id})
    thread.start()

    # Wait for child to finish
    thread.join()

    close = picoVNACOMObj.CloseVNA()
    print("closing of VNA " + str(close))

    return print("This works")

app = dash.Dash(__name__)
app.layout = html.Div(
    [
        dcc.Graph(id='live-graph', animate=False),
        dcc.Interval(
            id='graph-update',
            interval=5000,
            n_intervals=0
        ),
    ]
)

@app.callback(Output('live-graph', 'figure'),
        [Input('graph-update', 'n_intervals')])
def update_graph_scatter(n):
    pythoncom.CoInitialize()
    picoVNACOMObj = win32com.client.Dispatch(pythoncom.CoGetInterfaceAndReleaseStream(picoVNACOMObj_id, pythoncom.IID_IDispatch))
    x_frequency = picoVNACOMObj.measure_vna_frquency()
    y_s11 = picoVNACOMObj.measure_vna_ys11()
    print(x_frequency)
    print(y_s11)

    data = go.Scatter(
            x=x_frequency,
            y=y_s11,
            name='S11 Parameters of Curling Probe',
            mode='lines'
            )

    return {'data': [data], 'layout': go.Layout(xaxis=dict(range=[min(x_frequency), max(x_frequency)]),
                                                yaxis=dict(range=[min(y_s11), max(y_s11)]),
                                                xaxis_title=dict(text="Frequency (MHz)"),
                                                yaxis_title=dict(text="S11 Parameter"))}

if __name__ == '__main__':
    start()
    app.run_server(debug=True)

It doesn’t work. I tested a simpler code whereby my threaded function was not a dash one but a simple one that I made. I don’t get marshalling errors with it, so clearly this concept of joining threads for instantiated objects works. But how do I get it to work with Dash? How do I pass my object into the update_graph_scatter() so that it can be controlled there?

Please help. I’ve been stuck on this for a month now.