ConnectionRefusedError with pyvisa TCPIP SOCKET & Dash

A measuring instrument (Ahlborn ALMEMO 2690) connected via RS232 works with pyvisa & plotly Dash (tested simplified python code examples used):

import pyvisa
from pyvisa.constants import StopBits, Parity
import time
from dash import Dash, html, dcc, callback, Output, Input

rm = pyvisa.ResourceManager('@py')
# Ahlborn ALMEMO 2690 over RS232 @ 115200 bd 8N1
measuring_instrument = rm.open_resource('ASRL/dev/ttyS0::INSTR', baud_rate=115200, data_bits=8, parity=Parity.none, stop_bits=StopBits.one)
measuring_instrument.read_termination = '' # required character(s), see manual of measuring_instrument: none required for RS232
measuring_instrument.write_termination = '' # required character(s), see manual of measuring_instrument: none required
measuring_instrument.write('f1G02') # init_string, see manual of measuring_instrument
timer1 = time.time() # time.time() uses float in seconds: 1 = 1 s
cycle_time = 0.5 # measurement cycle time, given in seconds as float value
cycle_time_ms = int(cycle_time * 1000) # measurement cycle time, given in milliseconds (integer)

app = Dash(__name__)
app.layout = html.Div(
    html.Div([
        dcc.Interval(
            id='interval',
            interval = cycle_time_ms, #measurement cycle time, given in milliseconds (integer)
            n_intervals = 0
        ),
        html.Div(id='measurement_instrument_output'),
    ])
)

@app.callback(
    Output(component_id='measurement_instrument_output', component_property='children'),
    [Input(component_id='interval', component_property='n_intervals')]
)

def update(n_intervals):
    measuring_instrument.flush(pyvisa.constants.BufferOperation.discard_read_buffer) # clearing read_buffer, required
    measuring_instrument.write('S1') # send_string, see manual of measuring_instrument
    time.sleep(0.02) # depends on instrument transfer speed
    value0 = measuring_instrument.read(encoding='iso-8859-15') # value0 = send_string, should be neglected
    value1 = measuring_instrument.read(encoding='iso-8859-15') # value1 = response_string, required
    return (value1)

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

If connection of this measuring instrument is switched to ethernet it works with pyvisa and without Dash:

import pyvisa
import time

rm = pyvisa.ResourceManager('@py')
# Ahlborn ALMEMO 2690 over ethernet @ TCP/IP 192.168.0.240:10001
measuring_instrument = rm.open_resource('TCPIP::192.168.0.240::10001::SOCKET') # TCPIP::192.168.0.240::INSTR doesn't work!
measuring_instrument.read_termination = '\n' # required character(s), see manual of measuring_instrument: \n required for ethernet
measuring_instrument.write_termination = '' # required character(s), see manual of measuring_instrument: none required
measuring_instrument.write('f1G02') # init_string, see manual of measuring_instrument
timer1 = time.time() # time.time() uses float in seconds: 1 = 1 s
cycle_time = 0.5 # measurement cycle time, given in seconds as float value

while True:
    timer2 = time.time()
    diff = timer2 - timer1
    if diff >= cycle_time:
        timer1 = time.time()
        measuring_instrument.flush(pyvisa.constants.BufferOperation.discard_read_buffer) # clearing read_buffer, required
        measuring_instrument.write('S1') # send_string, see manual of measuring_instrument
        time.sleep(0.02) # depends on instrument transfer speed
        value0 = measuring_instrument.read(encoding='iso-8859-15') # value0 = send_string, should be neglected
        value1 = measuring_instrument.read(encoding='iso-8859-15') # value1 = response_string, required
        print(value1)

But it doesn’t work if Dash is added to pyvisa with use of TCPIP SOCKET:

import pyvisa
import time
from dash import Dash, html, dcc, callback, Output, Input

rm = pyvisa.ResourceManager('@py')
# Ahlborn ALMEMO 2690 over ethernet @ TCP/IP 192.168.0.240:10001
measuring_instrument = rm.open_resource('TCPIP::192.168.0.240::10001::SOCKET') # TCPIP::192.168.0.240::INSTR doesn't work!
measuring_instrument.read_termination = '\n' # required character(s), see manual of measuring_instrument: \n required for ethernet
measuring_instrument.write_termination = '' # required character(s), see manual of measuring_instrument: none required
measuring_instrument.write('f1G02') # init_string, see manual of measuring_instrument
timer1 = time.time() # time.time() uses float in seconds: 1 = 1 s
cycle_time = 0.5 # measurement cycle time, given in seconds as float value
cycle_time_ms = int(cycle_time * 1000) # measurement cycle time, given in milliseconds (integer)

app = Dash(__name__)
app.layout = html.Div(
    html.Div([
        dcc.Interval(
            id='interval',
            interval = cycle_time_ms, #measurement cycle time, given in milliseconds (integer)
            n_intervals = 0
        ),
        html.Div(id='measurement_instrument_output'),
    ])
)

@app.callback(
    Output(component_id='measurement_instrument_output', component_property='children'),
    [Input(component_id='interval', component_property='n_intervals')]
)

def update(n_intervals):
    measuring_instrument.flush(pyvisa.constants.BufferOperation.discard_read_buffer) # clearing read_buffer, required
    measuring_instrument.write('S1') # send_string, see manual of measuring_instrument
    time.sleep(0.02) # depends on instrument transfer speed
    value0 = measuring_instrument.read(encoding='iso-8859-15') # value0 = send_string, should be neglected
    value1 = measuring_instrument.read(encoding='iso-8859-15') # value1 = response_string, required
    return (value1)

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

Console shows error output:

Dash is running on http://127.0.0.1:8050/

  • Serving Flask app ‘pyVISA-example12’
  • Debug mode: on
    Traceback (most recent call last):
    File “/home/user/testing/pyVISA-example12.py”, line 10, in
    measuring_instrument.write(‘f1G02’) # init_string, see manual of measuring_instrument
    File “/home/user/.local/lib/python3.9/site-packages/pyvisa/resources/messagebased.py”, line 197, in write
    count = self.write_raw(message.encode(enco))
    File “/home/user/.local/lib/python3.9/site-packages/pyvisa/resources/messagebased.py”, line 157, in write_raw
    return self.visalib.write(self.session, message)[0]
    File “/home/user/.local/lib/python3.9/site-packages/pyvisa_py/highlevel.py”, line 543, in write
    written, status_code = self.sessions[session].write(data)
    File “/home/user/.local/lib/python3.9/site-packages/pyvisa_py/tcpip.py”, line 1246, in write
    size = self.interface.send(block)
    ConnectionRefusedError: [Errno 111] Connection refused

Tests with “tcpdump port 10001”:
Sucessfully running with pyvisa and without plotly Dash (second code example) gives tcpdump output like this:

18:13:12.213717 IP pc-008.ffi.52140 > localhost.10001: Flags [S], seq 1288963231, win 32120, options [mss 1460,sackOK,TS val 2662383994 ecr 0,nop,wscale 7], length 0
18:13:12.213921 IP localhost.10001 > pc-008.ffi.52140: Flags [S.], seq 109609790, ack 1288963232, win 2047, options [mss 1400], length 0
18:13:12.213935 IP pc-008.ffi.52140 > localhost.10001: Flags [.], ack 1, win 32120, length 0
18:13:12.213985 IP pc-008.ffi.52140 > localhost.10001: Flags [P.], seq 1:6, ack 1, win 32120, length 5
18:13:12.225047 IP localhost.10001 > pc-008.ffi.52140: Flags [.], ack 6, win 2047, length 0
18:13:12.246031 IP localhost.10001 > pc-008.ffi.52140: Flags [P.], seq 1:46, ack 6, win 2047, length 45
18:13:12.246035 IP pc-008.ffi.52140 > localhost.10001: Flags [.], ack 46, win 32075, length 0
18:13:12.814168 IP pc-008.ffi.52140 > localhost.10001: Flags [P.], seq 6:8, ack 46, win 32075, length 2
18:13:12.818130 IP localhost.10001 > pc-008.ffi.52140: Flags [P.], seq 46:50, ack 8, win 2047, length 4
18:13:12.818137 IP pc-008.ffi.52140 > localhost.10001: Flags [.], ack 50, win 32071, length 0
18:13:12.838996 IP localhost.10001 > pc-008.ffi.52140: Flags [P.], seq 50:86, ack 8, win 2047, length 36
18:13:12.839003 IP pc-008.ffi.52140 > localhost.10001: Flags [.], ack 86, win 32035, length 0
18:13:13.314131 IP pc-008.ffi.52140 > localhost.10001: Flags [P.], seq 8:10, ack 86, win 32035, length 2
18:13:13.318094 IP localhost.10001 > pc-008.ffi.52140: Flags [P.], seq 86:90, ack 10, win 2047, length 4
18:13:13.318101 IP pc-008.ffi.52140 > localhost.10001: Flags [.], ack 90, win 32031, length 0

Failing with pyvisa and with plotly Dash (third code example) gives tcpdump output like this:

18:13:41.013417 IP pc-008.ffi.46106 > localhost.10001: Flags [S], seq 1702851283, win 32120, options [mss 1460,sackOK,TS val 2662412794 ecr 0,nop,wscale 7], length 0
18:13:41.013622 IP localhost.10001 > pc-008.ffi.46106: Flags [S.], seq 119103457, ack 1702851284, win 2047, options [mss 1400], length 0
18:13:41.013636 IP pc-008.ffi.46106 > localhost.10001: Flags [.], ack 1, win 32120, length 0
18:13:41.013691 IP pc-008.ffi.46106 > localhost.10001: Flags [P.], seq 1:6, ack 1, win 32120, length 5
18:13:41.024431 IP localhost.10001 > pc-008.ffi.46106: Flags [.], ack 6, win 2047, length 0
18:13:41.045419 IP localhost.10001 > pc-008.ffi.46106: Flags [P.], seq 1:46, ack 6, win 2047, length 45
18:13:41.045427 IP pc-008.ffi.46106 > localhost.10001: Flags [.], ack 46, win 32075, length 0
18:13:41.438377 IP pc-008.ffi.46116 > localhost.10001: Flags [S], seq 391207644, win 32120, options [mss 1460,sackOK,TS val 2662413218 ecr 0,nop,wscale 7], length 0
18:13:41.438663 IP localhost.10001 > pc-008.ffi.46116: Flags [R.], seq 0, ack 391207645, win 0, length 0
18:13:41.499507 IP pc-008.ffi.46106 > localhost.10001: Flags [R.], seq 6, ack 46, win 32075, length 0

Presence of plotly Dash results in a second try with a SYN packet that is responded with two RST packets. This seems to be the problem and how can it be solved?

Using this code

import pyvisa
import time
from dash import Dash, html, dcc, callback, Output, Input

rm = pyvisa.ResourceManager('@py')
# Ahlborn ALMEMO 2690 over ethernet @ TCP/IP 192.168.0.240:10001
measuring_instrument = rm.open_resource('TCPIP0::192.168.0.240::10001::SOCKET') # TCPIP::192.168.0.240::INSTR doesn't work!
measuring_instrument.read_termination = '\r\n' # required character(s), see manual of measuring_instrument: \r\n required for ethernet
measuring_instrument.write_termination = '' # required character(s), see manual of measuring_instrument: none required
measuring_instrument.write('f1G02') # init_string, see manual of measuring_instrument
time.sleep(1)

# for debugging only
measuring_instrument.flush(pyvisa.constants.BufferOperation.discard_read_buffer) # clearing read_buffer, required
measuring_instrument.write('S1') # send_string, see manual of measuring_instrument
time.sleep(0.02) # depends on instrument transfer speed
value0 = measuring_instrument.read(encoding='iso-8859-15') # value0 = send_string, should be neglected
value1 = measuring_instrument.read(encoding='iso-8859-15') # value1 = response_string, required
print (value1)

cycle_time = 0.5 # measurement cycle time, given in seconds as float value
cycle_time_ms = int(cycle_time * 1000) # measurement cycle time, given in milliseconds (integer)

app = Dash(__name__)
app.layout = html.Div(
    html.Div([
        dcc.Interval(
            id='interval',
            interval = cycle_time_ms, #measurement cycle time, given in milliseconds (integer)
            n_intervals = 0
        ),
        html.Div(id='measurement_instrument_output'),
    ])
)

@app.callback(
    Output(component_id='measurement_instrument_output', component_property='children'),
    [Input(component_id='interval', component_property='n_intervals')]
)

def update(n_intervals):
    measuring_instrument.flush(pyvisa.constants.BufferOperation.discard_read_buffer) # clearing read_buffer, required
    measuring_instrument.write('S1') # send_string, see manual of measuring_instrument
    time.sleep(0.02) # depends on instrument transfer speed
    value0 = measuring_instrument.read(encoding='iso-8859-15') # value0 = send_string, should be neglected
    value1 = measuring_instrument.read(encoding='iso-8859-15') # value1 = response_string, required
    return (value1)

if __name__ == '__main__':
    app.run_server(port=8050, host='0.0.0.0', debug=True)

gives following console output:

;08.05.24 11:22:15.00;20,69;106,54
Dash is running on http://0.0.0.0:8050/

 * Serving Flask app 'pyVISA-example12'
 * Debug mode: on
Traceback (most recent call last):
  File "/mnt/exfat-data/Messtechnik/python/pyVISA-Ethernet/pyVISA-example12.py", line 10, in <module>
    measuring_instrument.write('f1G02') # init_string, see manual of measuring_instrument
  File "/home/user/.local/lib/python3.9/site-packages/pyvisa/resources/messagebased.py", line 197, in write
    count = self.write_raw(message.encode(enco))
  File "/home/user/.local/lib/python3.9/site-packages/pyvisa/resources/messagebased.py", line 157, in write_raw
    return self.visalib.write(self.session, message)[0]
  File "/home/user/.local/lib/python3.9/site-packages/pyvisa_py/highlevel.py", line 543, in write
    written, status_code = self.sessions[session].write(data)
  File "/home/user/.local/lib/python3.9/site-packages/pyvisa_py/tcpip.py", line 1246, in write
    size = self.interface.send(block)
ConnectionRefusedError: [Errno 111] Connection refused

;08.05.24 11:22:15.00;20,69;106,54
is expected output of print(value1) and indicates that program runs error-free until startup of Dash.

tcpdump port 10001 gives following console output:

tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
12:27:20.739871 IP pc-008.ffi.37168 > localhost.10001: Flags [S], seq 3917895631, win 32120, options [mss 1460,sackOK,TS val 926210130 ecr 0,nop,wscale 7], length 0
12:27:20.740238 IP localhost.10001 > pc-008.ffi.37168: Flags [S.], seq 5024773, ack 3917895632, win 2047, options [mss 1400], length 0
12:27:20.740252 IP pc-008.ffi.37168 > localhost.10001: Flags [.], ack 1, win 32120, length 0
12:27:20.740313 IP pc-008.ffi.37168 > localhost.10001: Flags [P.], seq 1:6, ack 1, win 32120, length 5
12:27:20.751683 IP localhost.10001 > pc-008.ffi.37168: Flags [.], ack 6, win 2047, length 0
12:27:20.849732 IP localhost.10001 > pc-008.ffi.37168: Flags [P.], seq 1:10, ack 6, win 2047, length 9
12:27:20.849739 IP pc-008.ffi.37168 > localhost.10001: Flags [.], ack 10, win 32111, length 0
12:27:20.870643 IP localhost.10001 > pc-008.ffi.37168: Flags [P.], seq 10:32, ack 6, win 2047, length 22
12:27:20.870649 IP pc-008.ffi.37168 > localhost.10001: Flags [.], ack 32, win 32089, length 0
12:27:21.841979 IP pc-008.ffi.37168 > localhost.10001: Flags [P.], seq 6:8, ack 32, win 32089, length 2
12:27:21.846778 IP localhost.10001 > pc-008.ffi.37168: Flags [P.], seq 32:36, ack 8, win 2047, length 4
12:27:21.846800 IP pc-008.ffi.37168 > localhost.10001: Flags [.], ack 36, win 32085, length 0
12:27:21.867866 IP localhost.10001 > pc-008.ffi.37168: Flags [P.], seq 36:73, ack 8, win 2047, length 37
12:27:21.867885 IP pc-008.ffi.37168 > localhost.10001: Flags [.], ack 73, win 32048, length 0
12:27:22.294691 IP pc-008.ffi.37180 > localhost.10001: Flags [S], seq 453407285, win 32120, options [mss 1460,sackOK,TS val 926211685 ecr 0,nop,wscale 7], length 0
12:27:22.294911 IP localhost.10001 > pc-008.ffi.37180: Flags [R.], seq 0, ack 453407286, win 0, length 0
12:27:22.355329 IP pc-008.ffi.37168 > localhost.10001: Flags [F.], seq 8, ack 73, win 32048, length 0
12:27:22.355627 IP localhost.10001 > pc-008.ffi.37168: Flags [F.], seq 73, ack 9, win 2047, length 0
12:27:22.355639 IP pc-008.ffi.37168 > localhost.10001: Flags [.], ack 74, win 32047, length 0

This line
12:27:22.294691 IP pc-008.ffi.37180 > localhost.10001: Flags [S], seq 453407285, win 32120, options [mss 1460,sackOK,TS val 926211685 ecr 0,nop,wscale 7], length 0
indicates that Dash startup triggers something to try to connect with measuring instrument. This try kills established connection between pyvisa and measuring instrument.

Hello @kraft-ffi,

Welcome to the community!

On your callback, did you try to use prevent_initial_call=True, this may be what you are running into an issue?

Use or no use of prevent_initial_call=True changes nothing.

My guess is that you can only have one connection at a time, I dont know why this is the case.

Following code is the sledgehammer method, but it works:

import pyvisa
import time
from dash import Dash, html, dcc, callback, Output, Input

cycle_time = 0.5 # measurement cycle time, given in seconds as float value
cycle_time_ms = int(cycle_time * 1000) # measurement cycle time, given in milliseconds (integer)

app = Dash(__name__)
app.layout = html.Div(
    html.Div([
        dcc.Interval(
            id='interval',
            interval = cycle_time_ms, #measurement cycle time, given in milliseconds (integer)
            n_intervals = 0
        ),
        html.Div(id='measurement_instrument_output'),
    ])
)

@app.callback(
    Output(component_id='measurement_instrument_output', component_property='children'),
    [Input(component_id='interval', component_property='n_intervals')]
)

def update(n_intervals):
    rm = pyvisa.ResourceManager('@py')
    # Ahlborn ALMEMO 2690 over ethernet @ TCP/IP 192.168.0.240:10001
    measuring_instrument = rm.open_resource('TCPIP0::192.168.0.240::10001::SOCKET') # TCPIP::192.168.0.240::INSTR doesn't work!
    measuring_instrument.read_termination = '\r\n' # required character(s), see manual of measuring_instrument: \r\n required for ethernet
    measuring_instrument.write_termination = '' # required character(s), see manual of measuring_instrument: none required
    measuring_instrument.write('f1G02') # init_string, see manual of measuring_instrument
    time.sleep(0.02) # depends on measuring_instrument transfer speed
    measuring_instrument.flush(pyvisa.constants.BufferOperation.discard_read_buffer) # clearing read_buffer, required
    measuring_instrument.write('S1') # send_string, see manual of measuring_instrument
    time.sleep(0.02) # depends on measuring_instrument transfer speed
    value0 = measuring_instrument.read(encoding='iso-8859-15') # value0 = send_string, should be neglected
    value1 = measuring_instrument.read(encoding='iso-8859-15') # value1 = response_string, required
    measuring_instrument.write('X') # stop data transfer
    rm.close() # close & remove measuring_instrument = TCP/IP socket
    return (value1)

if __name__ == '__main__':
    app.run_server(port=8050, host='0.0.0.0', debug=True)

Code given above is not suitable for measurements with very short measurement cycle times due to its large “overhead”. Switch to native RS232 connections is highly recommended for measurements with very short measurement cycle times to avoid additional communication overhead because this measuring instrument has a RS232 interface only. Available connecting devices over ethernet, bluetooth or USB are realized with converters to RS232 interface of this measuring instrument. Only USB works fully transparent. pyvisa code for serial connection has to be used, not code for USB! Only /dev/ttyS has to be replaced with /dev/ttyUSB.