@@ -19,7 +19,13 @@ import {
1919 yesToBoolean ,
2020} from "@/app/components/Instrument" ;
2121import useWebSocket from "react-use-websocket" ;
22- import { instListPV , instListSubscription , socketURL } from "@/app/commonVars" ;
22+ import {
23+ instListPV ,
24+ instListSubscription ,
25+ socketURL ,
26+ webSocketReconnectAttempts ,
27+ webSocketReconnectInterval ,
28+ } from "@/app/commonVars" ;
2329import {
2430 dehex_and_decompress ,
2531 instListFromBytes ,
@@ -36,11 +42,11 @@ import Groups from "@/app/components/Groups";
3642export function InstrumentData ( { instrumentName } : { instrumentName : string } ) {
3743 const [ showHiddenBlocks , setShowHiddenBlocks ] = useState ( false ) ;
3844 const CONFIG_DETAILS = "CS:BLOCKSERVER:WD_CONF_DETAILS" ;
39- const [ instlist , setInstlist ] = useState < instList | null > ( null ) ;
4045 const [ currentInstrument , setCurrentInstrument ] = useState < Instrument | null > (
4146 null ,
4247 ) ;
4348 const [ lastUpdate , setLastUpdate ] = useState < string > ( "" ) ;
49+ const [ webSockErr , setWebSockErr ] = useState ( "" ) ;
4450
4551 const instName = instrumentName ;
4652
@@ -58,133 +64,129 @@ export function InstrumentData({ instrumentName }: { instrumentName: string }) {
5864 lastJsonMessage : IfcPVWSMessage ;
5965 } = useWebSocket ( socketURL , {
6066 shouldReconnect : ( closeEvent ) => true ,
61- } ) ;
62-
63- useEffect ( ( ) => {
64- // This is an initial useEffect to subscribe to lots of PVs including the instlist.
65- sendJsonMessage ( instListSubscription ) ;
66-
67- if ( instName == "" || instName == null || instlist == null ) {
68- return ;
69- }
70-
71- let prefix = getPrefix ( instlist , instName ) ;
72-
73- if ( ! currentInstrument ) {
74- let instrument = new Instrument ( prefix ) ;
75- setCurrentInstrument ( instrument ) ;
76-
77- sendJsonMessage ( {
78- type : PVWSRequestType . subscribe ,
79- pvs : [ `${ prefix } ${ CONFIG_DETAILS } ` ] ,
80- } ) ;
67+ onOpen : ( ) => {
68+ setWebSockErr ( "" ) ;
69+ setLastUpdate ( "" ) ; // if this is called on a reconnect, we want to clear the last update so we can re-subscribe to everything again
70+ sendJsonMessage ( instListSubscription ) ;
71+ } ,
72+ onMessage : ( m ) => {
73+ const updatedPV : IfcPVWSMessage = JSON . parse ( m . data ) ;
74+ const updatedPVName : string = updatedPV . pv ;
75+ const updatedPVbytes : string | null | undefined = updatedPV . b64byt ;
76+
77+ if ( updatedPVName == instListPV && updatedPVbytes != null ) {
78+ const instlist = instListFromBytes ( updatedPVbytes ) ;
79+ const prefix = getPrefix ( instlist , instName ) ;
80+ const instrument = new Instrument ( prefix ) ;
81+ setCurrentInstrument ( instrument ) ;
8182
82- // subscribe to dashboard and run info PVs
83- for ( const pv of instrument . runInfoPVs . concat (
84- instrument . dashboard . flat ( 3 ) ,
85- ) ) {
8683 sendJsonMessage ( {
8784 type : PVWSRequestType . subscribe ,
88- pvs : [ pv . pvaddress ] ,
85+ pvs : [ ` ${ prefix } ${ CONFIG_DETAILS } ` ] ,
8986 } ) ;
90- }
91- }
92- } , [ instlist , instName , sendJsonMessage , currentInstrument ] ) ;
93-
94- useEffect ( ( ) => {
95- // This gets run whenever there is a PV update ie. when lastJsonMessage changes.
96- if ( ! lastJsonMessage ) {
97- return ;
98- }
99- const updatedPV : IfcPVWSMessage = lastJsonMessage ;
100- const updatedPVName : string = updatedPV . pv ;
101- const updatedPVbytes : string | null | undefined = updatedPV . b64byt ;
102-
103- if ( updatedPVName == instListPV && updatedPVbytes != null ) {
104- setInstlist ( instListFromBytes ( updatedPVbytes ) ) ;
105- return ;
106- }
107-
108- if ( ! currentInstrument ) {
109- return ;
110- }
11187
112- if (
113- updatedPVName == `${ currentInstrument . prefix } ${ CONFIG_DETAILS } ` &&
114- updatedPVbytes != null
115- ) {
116- // config change, reset instrument groups
117- if ( updatedPVbytes == lastUpdate ) {
118- // config hasnt actually changed so do nothing
88+ // subscribe to dashboard and run info PVs
89+ for ( const pv of instrument . runInfoPVs . concat (
90+ instrument . dashboard . flat ( 3 ) ,
91+ ) ) {
92+ sendJsonMessage ( {
93+ type : PVWSRequestType . subscribe ,
94+ pvs : [ pv . pvaddress ] ,
95+ } ) ;
96+ }
11997 return ;
12098 }
121- setLastUpdate ( updatedPVbytes ) ;
122- const res = dehex_and_decompress ( atob ( updatedPVbytes ) ) ;
123- currentInstrument . groups = getGroupsWithBlocksFromConfigOutput (
124- JSON . parse ( res ) ,
125- sendJsonMessage ,
126- currentInstrument . prefix ,
127- ) ;
128- } else {
129- const pvVal = getPvValue ( updatedPV ) ;
13099
131- if ( pvVal == undefined ) {
132- console . debug ( `initial/blank message from ${ updatedPVName } ` ) ;
100+ if ( ! currentInstrument ) {
133101 return ;
134102 }
135103
136- // Check if this is a dashboard, run info, or block PV update.
137- const pv =
138- findPVInDashboard ( currentInstrument . dashboard , updatedPVName ) ||
139- findPVByAddress ( currentInstrument . runInfoPVs , updatedPVName ) ||
140- findPVInGroups (
141- currentInstrument . groups ,
104+ if (
105+ updatedPVName == `${ currentInstrument . prefix } ${ CONFIG_DETAILS } ` &&
106+ updatedPVbytes != null
107+ ) {
108+ // config change, reset instrument groups
109+ if ( updatedPVbytes == lastUpdate ) {
110+ // config hasnt actually changed so do nothing
111+ return ;
112+ }
113+ setLastUpdate ( updatedPVbytes ) ;
114+ const res = dehex_and_decompress ( atob ( updatedPVbytes ) ) ;
115+ currentInstrument . groups = getGroupsWithBlocksFromConfigOutput (
116+ JSON . parse ( res ) ,
117+ sendJsonMessage ,
142118 currentInstrument . prefix ,
143- updatedPVName ,
144119 ) ;
145- if ( pv ) {
146- storePrecision ( updatedPV , pv ) ;
147- pv . value = toPrecision ( pv , pvVal ) ;
148- if ( updatedPV . seconds ) pv . updateSeconds = updatedPV . seconds ;
149- if ( updatedPV . units ) pv . units = updatedPV . units ;
150- if ( updatedPV . severity ) pv . severity = updatedPV . severity ;
151120 } else {
152- // OK, we haven't found the block, but we may have an update for
153- // its object such as its run control status or SP:RBV
154- if ( updatedPVName . endsWith ( RC_INRANGE ) ) {
155- const underlyingBlock = findPVInGroups (
156- currentInstrument . groups ,
157- currentInstrument . prefix ,
158- updatedPVName . replace ( RC_INRANGE , "" ) ,
159- ) ;
160- if ( underlyingBlock )
161- underlyingBlock . runcontrol_inrange = yesToBoolean ( pvVal ) ;
162- } else if ( updatedPVName . endsWith ( RC_ENABLE ) ) {
163- const underlyingBlock = findPVInGroups (
164- currentInstrument . groups ,
165- currentInstrument . prefix ,
166- updatedPVName . replace ( RC_ENABLE , "" ) ,
167- ) ;
168- if ( underlyingBlock )
169- underlyingBlock . runcontrol_enabled = yesToBoolean ( pvVal ) ;
170- } else if ( updatedPVName . endsWith ( SP_RBV ) ) {
171- const underlyingBlock = findPVInGroups (
121+ const pvVal = getPvValue ( updatedPV ) ;
122+
123+ if ( pvVal == undefined ) {
124+ console . debug ( `initial/blank message from ${ updatedPVName } ` ) ;
125+ return ;
126+ }
127+
128+ // Check if this is a dashboard, run info, or block PV update.
129+ const pv =
130+ findPVInDashboard ( currentInstrument . dashboard , updatedPVName ) ||
131+ findPVByAddress ( currentInstrument . runInfoPVs , updatedPVName ) ||
132+ findPVInGroups (
172133 currentInstrument . groups ,
173134 currentInstrument . prefix ,
174- updatedPVName . replace ( SP_RBV , "" ) ,
135+ updatedPVName ,
175136 ) ;
176- if ( underlyingBlock )
177- underlyingBlock . sp_value = toPrecision ( underlyingBlock , pvVal ) ;
137+ if ( pv ) {
138+ storePrecision ( updatedPV , pv ) ;
139+ pv . value = toPrecision ( pv , pvVal ) ;
140+ if ( updatedPV . seconds ) pv . updateSeconds = updatedPV . seconds ;
141+ if ( updatedPV . units ) pv . units = updatedPV . units ;
142+ if ( updatedPV . severity ) pv . severity = updatedPV . severity ;
178143 } else {
179- console . warn (
180- `update from unknown PV: ${ updatedPVName } with value ${ pvVal } ` ,
181- ) ;
144+ // OK, we haven't found the block, but we may have an update for
145+ // its object such as its run control status or SP:RBV
146+ if ( updatedPVName . endsWith ( RC_INRANGE ) ) {
147+ const underlyingBlock = findPVInGroups (
148+ currentInstrument . groups ,
149+ currentInstrument . prefix ,
150+ updatedPVName . replace ( RC_INRANGE , "" ) ,
151+ ) ;
152+ if ( underlyingBlock )
153+ underlyingBlock . runcontrol_inrange = yesToBoolean ( pvVal ) ;
154+ } else if ( updatedPVName . endsWith ( RC_ENABLE ) ) {
155+ const underlyingBlock = findPVInGroups (
156+ currentInstrument . groups ,
157+ currentInstrument . prefix ,
158+ updatedPVName . replace ( RC_ENABLE , "" ) ,
159+ ) ;
160+ if ( underlyingBlock )
161+ underlyingBlock . runcontrol_enabled = yesToBoolean ( pvVal ) ;
162+ } else if ( updatedPVName . endsWith ( SP_RBV ) ) {
163+ const underlyingBlock = findPVInGroups (
164+ currentInstrument . groups ,
165+ currentInstrument . prefix ,
166+ updatedPVName . replace ( SP_RBV , "" ) ,
167+ ) ;
168+ if ( underlyingBlock )
169+ underlyingBlock . sp_value = toPrecision ( underlyingBlock , pvVal ) ;
170+ } else {
171+ console . warn (
172+ `update from unknown PV: ${ updatedPVName } with value ${ pvVal } ` ,
173+ ) ;
174+ }
182175 }
183176 }
184- }
185- } , [ lastJsonMessage , currentInstrument , sendJsonMessage , lastUpdate ] ) ;
177+ } ,
178+ onError : ( err ) => {
179+ setWebSockErr (
180+ "Failed to connect to websocket - please check your network connection and contact Experiment Controls if this persists." ,
181+ ) ;
182+ } ,
183+ share : true ,
184+ retryOnError : true ,
185+ reconnectInterval : webSocketReconnectInterval ,
186+ reconnectAttempts : webSocketReconnectAttempts ,
187+ } ) ;
186188
187- if ( ! instName || ! currentInstrument ) {
189+ if ( ! currentInstrument ) {
188190 return < h1 > Loading...</ h1 > ;
189191 }
190192 return (
@@ -194,6 +196,7 @@ export function InstrumentData({ instrumentName }: { instrumentName: string }) {
194196 instName = { instName }
195197 runInfoPVs = { currentInstrument . runInfoPVs }
196198 />
199+ { webSockErr && < h1 className = { "text-red-600" } > { webSockErr } </ h1 > }
197200 < div className = "flex gap-2 ml-2 md:flex-row flex-col" >
198201 < CheckToggle
199202 checked = { showHiddenBlocks }
0 commit comments