Hello,
I think I misunderstood what are websockets, how they work and/or what they do.
In my mind, set_props was sending the state of a component to the server and get_prop was retrieving such state.
The monitoring system I’m working on is supposed to be open on multiple different machines at the same time. What I’m trying to do is have buttons to turn on/off an alarm system. So far, I managed but then, when a user set the alarm to ON, I wanted the buttons on the other instances of the dash app (i.e. on other machines) to check the status of such button and update their interface to match the current alarm status.
Here is a short usable example of what I’m trying to do:
#!/home/oper/.venv/bin/python3
import asyncio
import dash_bootstrap_components as dbc
from dash import (
callback,
ctx,
Dash,
html,
Input,
set_props,
)
status = dict(nn=None, ns=None)
antennas = ['nn', 'ns']
app = Dash(external_stylesheets=[dbc.themes.DARKLY], backend='fastapi')
app.layout = html.Div(
[
html.H2('Menu', className='display-4'),
html.Hr(),
html.Div([
html.Div([html.Div('NN Alarm Status', className='lead'),
html.Div(id='nn-status')], className='hstack'),
html.Div(dbc.Button(id='nn-alarm-switch')),
]),
html.Div([
html.Div([html.Div('NS Alarm Status', className='lead'),
html.Div(id='ns-status')], className='hstack'),
html.Div(dbc.Button(id='ns-alarm-switch')),
]),
])
# ----------------------
# Change alarm state on button click
# ----------------------
@callback(
Input(component_id='nn-alarm-switch', component_property='n_clicks'),
Input(component_id='ns-alarm-switch', component_property='n_clicks'),
prevent_initial_call=True,
websocket=True,
)
async def change_alarm_state(nn_button, ns_button):
button = ctx.triggered_id
ant = ctx.triggered_id.split('-')[0]
print(f'{button} alarm button clicked, current status is {status[ant]}')
if status[ant] == 'On':
status[ant] = 'Off'
elif status[ant] == 'Off':
status[ant] = 'On'
set_props(button, {'children': status[ant]})
await asyncio.sleep(1)
#--------------------
# Check the alarm status (on/off) and change the button accordingly)
#--------------------
@callback(persistent=True,
websocket=True)
async def check_alarm_status():
alarm = False
ws = ctx.websocket
for i in antennas: # Check buttons for both antennas
initial_status = await ws.get_prop(f'{i}-alarm-switch', 'children')
if initial_status is None:
initial_status = 'Off'
status[i] = initial_status
print(f'{i}-alarm-switch should be {initial_status}')
set_props(f'{i}-alarm-switch', {'children': initial_status})
while not ws.is_shutdown:
print('Checking alarm status')
print(f'Current status is {status[i]}')
for i in antennas:
status[i] = await ws.get_prop(f'{i}-alarm-switch', 'children')
if status[i] is not None:
set_props(f'{i}-alarm-switch', {'children': status[i]})
print(f'After check status is {status}')
await asyncio.sleep(2)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=3000)
I tried to clear it of all things not related to the buttons, sorry if it’s still a bit long. For context, I’m working with two radiotelescopes (antennas), named NN and NS, and I’d like to have an alarm system independant for both of them.
With what I have at the moment, the buttons turn ON/OFF when clicked, no issues there, but then the clients opened on other machines are not updated as I thought they would.
That’s why I think I misunderstood the use of websockets.
Also, when writing this I realised that my status variable doesn’t get updated outside of the callback and so is not the same for both callbacks…
So my question is, are websockets supposed to be used like this ? Are they usable to communicates with different instances of a dash app ?
Thanks for your time.