Coverage for /home/pi/Software/model-railway-signalling/model_railway_signals/editor/objects/objects_signals.py: 99%

268 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2024-04-10 15:08 +0100

1#------------------------------------------------------------------------------------ 

2# This module contains all the functions for managing Signal objects. And also 

3# Track Sensors as they are inherently linked to signal passed/approached events 

4#------------------------------------------------------------------------------------ 

5# 

6# External API functions / objects intended for use by other editor modules: 

7# create_signal(type,subtype) - Create a default signal object on the schematic 

8# delete_signal(object_id) - Hard Delete an object when deleted from the schematic 

9# update_signal(obj_id,new_obj) - Update the configuration of an existing signal object 

10# paste_signal(object) - Paste a copy of an object to create a new one (returns new object_id) 

11# delete_signal_object(object_id) - soft delete the drawing object (prior to recreating) 

12# redraw_signal_object(object_id) - Redraw the object on the canvas following an update 

13# default_signal_object - The dictionary of default values for the object 

14# mqtt_update_signals(pub_list, sub_list) - Configure MQTT publish/subscribe 

15# mqtt_update_sensors(pub_list, sub_list) - Configure MQTT publish/subscribe 

16# update_local_sensors(trigger,timeout,mappings) - Configure local track sensors 

17# remove_references_to_point (point_id) - remove point references from the interlocking tables 

18# update_references_to_point(old_pt_id, new_pt_id) - update point_id in the interlocking tables 

19# remove_references_to_section (sec_id) - remove section references from the interlocking tables 

20# update_references_to_section(old_id, new_id) - update section_id in the interlocking tables 

21# remove_references_to_instrument (inst_id) - remove instr references from the interlocking tables 

22# update_references_to_instrument(old_id, new_id) - update inst_id in the interlocking tables 

23# 

24# Makes the following external API calls to other editor modules: 

25# objects_common.set_bbox - to create/update the boundary box for the schematic object 

26# objects_common.find_initial_canvas_position - to find the next 'free' canvas position 

27# objects_common.new_item_id - to find the next 'free' item ID when creating objects 

28# objects_common.signal - To get The Object_ID for a given Item_ID 

29# objects_points.reset_point_interlocking_tables() - recalculate interlocking tables  

30# 

31# Accesses the following external editor objects directly: 

32# run_layout.schematic_callback - setting the object callbacks when created/recreated 

33# objects_common.schematic_objects - the master dictionary of Schematic Objects 

34# objects_common.signal_index - The Index of Signal Objects (for iterating) 

35# objects_common.default_object - The common dictionary element for all objects 

36# objects_common.object_type - The Enumeration of supported objects 

37# objects_common.canvas - Reference to the Tkinter drawing canvas 

38# 

39# Accesses the following external library objects directly: 

40# signals_common.sig_exists - Common function to see if a given item exists 

41# signals_common.sig_type - for setting the enum value when creating the object 

42# signals_colour_lights.signal_sub_type - for setting the enum value when creating the object 

43# signals_semaphores.semaphore_sub_type - for setting the enum value when creating the object 

44# signals_ground_position.ground_pos_sub_type - for setting the enum value when creating the object 

45# signals_ground_disc.ground_disc_sub_type - for setting the enum value when creating the object 

46# 

47# Makes the following external API calls to library modules: 

48# signals.update_signal(id) - To set the initial colour light signal aspect following creation 

49# signals.set_route(id,route) - To set the initial route for a signal following creation 

50# signals_colour_lights.create_colour_light_signal - To create the library object (create or redraw) 

51# signals_semaphores.create_semaphore_signal - To create the library object (create or redraw) 

52# signals_ground_position.create_ground_position_signal - To create the library object (create or redraw) 

53# signals_ground_disc.create_ground_disc_signal - To create the library object (create or redraw) 

54# signals_common.get_tags(id) - get the canvas 'tags' for the signal drawing objects 

55# signals_common.delete_signal(id) - delete library drawing object (part of soft delete) 

56# signals.reset_mqtt_configuration - reset MQTT networking prior to reconfiguration 

57# signals.set_signals_to_publish_state(IDs) - configure MQTT networking 

58# signals.subscribe_to_remote_signal(ID,callback) - configure MQTT networking 

59# dcc_control.delete_signal_mapping - delete the existing DCC mapping for the signal 

60# dcc_control.map_dcc_signal - to create a new DCC mapping for the signal 

61# dcc_control.map_semaphore_signal - to create a new DCC mapping for the signal 

62# gpio_sensors.add_gpio_sensor_callback - To set up a GPIO Sensor triggered callback 

63# gpio_sensors.remove_gpio_sensor_callback - To remove any GPIO Sensor triggered callbacks 

64# 

65#------------------------------------------------------------------------------------ 

66 

67import uuid 

68import copy 

69 

70from ...library import signals 

71from ...library import signals_common 

72from ...library import signals_colour_lights 

73from ...library import signals_semaphores 

74from ...library import signals_ground_position 

75from ...library import signals_ground_disc 

76from ...library import dcc_control 

77from ...library import gpio_sensors 

78 

79from . import objects_common 

80from . import objects_points 

81from .. import run_layout 

82 

83#------------------------------------------------------------------------------------ 

84# Default Signal Objects (i.e. state at creation) 

85#------------------------------------------------------------------------------------ 

86 

87# This is the default signal object definition 

88default_signal_object = copy.deepcopy(objects_common.default_object) 

89default_signal_object["item"] = objects_common.object_type.signal 

90default_signal_object["itemtype"] = signals_common.sig_type.colour_light.value 

91default_signal_object["itemsubtype"] = signals_colour_lights.signal_sub_type.four_aspect.value 

92default_signal_object["orientation"] = 0 

93default_signal_object["subsidary"] = [False,0] # [has_subsidary, dcc_address] 

94default_signal_object["theatreroute"] = False 

95default_signal_object["feathers"] = [False,False,False,False,False] # [MAIN,LH1,LH2,RH1,RH2] 

96default_signal_object["dccautoinhibit"] = False 

97# Interlock a distant signal with all home signals ahead 

98default_signal_object["interlockahead"] = False 

99# The signal arms table comprises a list of route elements: [main, LH1, LH2, RH1, RH2] 

100# Each Route element comprises a list of signal elements: [sig, sub, dist] 

101# Each signal element comprises [enabled/disabled, associated DCC address] 

102default_signal_object["sigarms"] = [ 

103 [ [True,0],[False,0],[False,0] ], 

104 [ [False,0],[False,0],[False,0] ], 

105 [ [False,0],[False,0],[False,0] ], 

106 [ [False,0],[False,0],[False,0] ], 

107 [ [False,0],[False,0],[False,0] ] ] 

108# The DCC aspects table comprises a list of DCC command sequences: [grn, red, ylw, dylw, fylw, fdylw] 

109# Each DCC command sequence comprises a list of DCC commands [dcc1, dcc2, dcc3, dcc4, dcc5, dcc6] 

110# Each DCC command comprises: [DCC address, DCC state] 

111default_signal_object["dccaspects"] = [ 

112 [[0,False],[0,False],[0,False],[0,False],[0,False],[0,False]], 

113 [[0,False],[0,False],[0,False],[0,False],[0,False],[0,False]], 

114 [[0,False],[0,False],[0,False],[0,False],[0,False],[0,False]], 

115 [[0,False],[0,False],[0,False],[0,False],[0,False],[0,False]], 

116 [[0,False],[0,False],[0,False],[0,False],[0,False],[0,False]], 

117 [[0,False],[0,False],[0,False],[0,False],[0,False],[0,False]] ] 

118# The DCC Feathers table comprises a list of DCC command sequences: [dark, main, lh1, lh2, rh1, rh2] 

119# Note that 'dark' is the DCC command sequence to inhibit all route indications 

120# Each DCC command sequence comprises a list of DCC commands: [dcc1, dcc2, dcc3, dcc4, dcc5, dcc6] 

121# Each DCC command comprises: [DCC address, DCC state] 

122default_signal_object["dccfeathers"] = [ 

123 [[0,False],[0,False],[0,False],[0,False],[0,False],[0,False]], 

124 [[0,False],[0,False],[0,False],[0,False],[0,False],[0,False]], 

125 [[0,False],[0,False],[0,False],[0,False],[0,False],[0,False]], 

126 [[0,False],[0,False],[0,False],[0,False],[0,False],[0,False]], 

127 [[0,False],[0,False],[0,False],[0,False],[0,False],[0,False]], 

128 [[0,False],[0,False],[0,False],[0,False],[0,False],[0,False]] ] 

129# The DCC Theatre table comprises a list of route elements: [dark, main, lh1, lh2, rh1, rh2] 

130# Note that 'dark' is the DCC route element to inhibit all route indications ('#') 

131# Each route element comprises: [character to be displayed, associated DCC command sequence] 

132# Each DCC command sequence comprises a list of DCC commands: [dcc1, dcc2, dcc3, dcc4, dcc5, dcc6] 

133# Each DCC command comprises: [DCC address, DCC state] 

134default_signal_object["dcctheatre"] = [ 

135 ["#", [[0,False],[0,False],[0,False],[0,False],[0,False],[0,False]]], 

136 ["", [[0,False],[0,False],[0,False],[0,False],[0,False],[0,False]]], 

137 ["", [[0,False],[0,False],[0,False],[0,False],[0,False],[0,False]]], 

138 ["", [[0,False],[0,False],[0,False],[0,False],[0,False],[0,False]]], 

139 ["", [[0,False],[0,False],[0,False],[0,False],[0,False],[0,False]]], 

140 ["", [[0,False],[0,False],[0,False],[0,False],[0,False],[0,False]]] ] 

141# This is the default point interlocking table for a signal 

142# The table comprises a list of route elements: [main, lh1, lh2, rh1, rh2] 

143# Each route element comprises: [[p1, p2, p3, p4, p5, p6] sig_id, block_id] 

144# Where Each point element (in the list of points) comprises [point_id, point_state] 

145# Note that Sig IDs in this case are strings (local or remote IDs) 

146default_signal_object["pointinterlock"] = [ 

147 [[[0,False],[0,False],[0,False],[0,False],[0,False],[0,False]],"",0], 

148 [[[0,False],[0,False],[0,False],[0,False],[0,False],[0,False]],"",0], 

149 [[[0,False],[0,False],[0,False],[0,False],[0,False],[0,False]],"",0], 

150 [[[0,False],[0,False],[0,False],[0,False],[0,False],[0,False]],"",0], 

151 [[[0,False],[0,False],[0,False],[0,False],[0,False],[0,False]],"",0] ] 

152# This is the default Track Section interlocking table for a signal 

153# Track Section interlocking table comprises a list of routes: [MAIN, LH1, LH2, RH1, RH2] 

154# Each route element contains a list of interlocked sections for that route [t1,t2,t3] 

155# Each entry is the ID of a (loacl) track section the signal is to be interlocked with 

156default_signal_object["trackinterlock"] = [ [0,0,0], [0,0,0], [0,0,0], [0,0,0], [0,0,0] ] 

157# This is the default opposing signal interlocking table for a signal 

158# The table comprises a list of route elements [main, lh1, lh2, rh1, rh2] 

159# Each route element comprises a list of signals [sig1, sig2, sig3, sig4] 

160# Each signal element comprises [sig_id, [main, lh1, lh2, rh1, rh2]] 

161# Where each route element is a boolean value (True or False) 

162default_signal_object["siginterlock"] = [ 

163 [ [0, [False, False, False, False, False]], 

164 [0, [False, False, False, False, False]], 

165 [0, [False, False, False, False, False]], 

166 [0, [False, False, False, False, False]] ], 

167 [ [0, [False, False, False, False, False]], 

168 [0, [False, False, False, False, False]], 

169 [0, [False, False, False, False, False]], 

170 [0, [False, False, False, False, False]] ], 

171 [ [0, [False, False, False, False, False]], 

172 [0, [False, False, False, False, False]], 

173 [0, [False, False, False, False, False]], 

174 [0, [False, False, False, False, False]] ], 

175 [ [0, [False, False, False, False, False]], 

176 [0, [False, False, False, False, False]], 

177 [0, [False, False, False, False, False]], 

178 [0, [False, False, False, False, False]] ], 

179 [ [0, [False, False, False, False, False]], 

180 [0, [False, False, False, False, False]], 

181 [0, [False, False, False, False, False]], 

182 [0, [False, False, False, False, False]] ] ] 

183# Set the default route selections for the signal 

184default_signal_object["sigroutes"] = [True,False,False,False,False] 

185default_signal_object["subroutes"] = [False,False,False,False,False] 

186# Set the default automation tables for the signal 

187default_signal_object["passedsensor"] = [True,""] # [button, linked track sensor] 

188default_signal_object["approachsensor"] = [False,""] # [button, linked track sensor] 

189# Track sections is a list of [section_behind, sections_ahead] 

190# sections_ahead is a list of the available signal routes [MAIN,LH1,LH2,RH1,RH2] 

191# each route element comprises a list of track sections [T1, T2, T3] 

192default_signal_object["tracksections"] = [0, [ [0,0,0], [0,0,0], [0,0,0], [0,0,0], [0,0,0]]] 

193# General automation settings for the signal 

194# 'overrideahead' will override distant if any home signals ahead are at DANGER 

195default_signal_object["fullyautomatic"] = False # Main signal is automatic (no button) 

196default_signal_object["distautomatic"] = False # Semaphore associated distant is automatic 

197default_signal_object["overrideahead"] = False 

198default_signal_object["overridesignal"] = False 

199# Approach_Control comprises a list of routes [MAIN, LH1, LH2, RH1, RH2] 

200# Each element represents the approach control mode that has been set 

201# release_on_red=1, release_on_yel=2, released_on_red_home_ahead=3 

202default_signal_object["approachcontrol"] = [0, 0, 0, 0, 0] 

203# A timed_sequence comprises a list of routes [MAIN, LH1, LH2, RH1, RH2] 

204# Each route comprises a list of [selected, sig_id,start_delay, time_delay) 

205default_signal_object["timedsequences"] = [ [False, 0, 0, 0], 

206 [False, 0, 0, 0], 

207 [False, 0, 0, 0], 

208 [False, 0, 0, 0], 

209 [False, 0, 0, 0] ] 

210 

211#------------------------------------------------------------------------------------ 

212# Internal Helper function to test if a semaphore has an associated distant signal 

213#------------------------------------------------------------------------------------ 

214 

215def has_associated_distant(object_id): 

216 return ( objects_common.schematic_objects[object_id]["sigarms"][0][2][0] or 

217 objects_common.schematic_objects[object_id]["sigarms"][1][2][0] or 

218 objects_common.schematic_objects[object_id]["sigarms"][2][2][0] or 

219 objects_common.schematic_objects[object_id]["sigarms"][3][2][0] or 

220 objects_common.schematic_objects[object_id]["sigarms"][4][2][0] ) 

221 

222#------------------------------------------------------------------------------------ 

223# Internal function to Remove any references to a signal (on deletion) 

224# Signal 'pointinterlock' comprises a list of routes: [main, lh1, lh2, rh1, rh2] 

225# Each route element comprises: [[p1, p2, p3, p4, p5, p6, p7], sig_id, block_id] 

226# Where sig_id in this case is a string (for local or remote signals) 

227# Signal 'siginterlock' comprises a list of routes [main, lh1, lh2, rh1, rh2] 

228# Each route element comprises a list of signals [sig1, sig2, sig3, sig4] 

229# Each signal element comprises [sig_id, [main, lh1, lh2, rh1, rh2]] 

230# Where each route element is a boolean value (True or False) 

231#------------------------------------------------------------------------------------ 

232 

233def remove_references_to_signal(deleted_sig_id:int): 

234 for signal_id in objects_common.signal_index: 

235 # Get the Object ID for the signal 

236 sig_object = objects_common.signal(signal_id) 

237 # Remove any references from the signal ahead on the interlocked routes 

238 list_of_interlocked_point_routes = objects_common.schematic_objects[sig_object]["pointinterlock"] 

239 for index1, interlocked_route in enumerate(list_of_interlocked_point_routes): 

240 if interlocked_route[1] == str(deleted_sig_id): 

241 objects_common.schematic_objects[sig_object]["pointinterlock"][index1][1] = "" 

242 # Remove and references from the conflicting signals 

243 list_of_interlocked_signal_routes = objects_common.schematic_objects[sig_object]["siginterlock"] 

244 # Iterate through the list of routes in the interlocking table 

245 for index1, interlocked_route in enumerate(list_of_interlocked_signal_routes): 

246 # Each route contains a list of up to 4 conflicting signals 

247 list_of_conflicting_signals = list_of_interlocked_signal_routes[index1] 

248 # Create a new 'blank' list for copying the signals (that haven't been deleted) across 

249 # We do this to 'tidy up' the list (i.e. remove the 'blanks' caused by signal removals) 

250 null_entry = [0, [False, False, False, False, False]] 

251 new_list_of_conflicting_signals = [null_entry, null_entry, null_entry, null_entry] 

252 index2 = 0 

253 # Iterate through each signal on the route in the interlocking table 

254 # to build up the new list of signals (that are to be retained) 

255 for conflicting_signal in list_of_conflicting_signals: 

256 if conflicting_signal[0] != deleted_sig_id: 

257 new_list_of_conflicting_signals[index2] = conflicting_signal 

258 index2 = index2 + 1 

259 # replace the list of conflicting signals 

260 objects_common.schematic_objects[sig_object]["siginterlock"][index1] = new_list_of_conflicting_signals 

261 # Remove any "Trigger Timed signal" references to the signal 

262 list_of_timed_sequences = objects_common.schematic_objects[sig_object]["timedsequences"] 

263 for index1, timed_sequence in enumerate(list_of_timed_sequences): 

264 if timed_sequence[1] == deleted_sig_id: 

265 objects_common.schematic_objects[sig_object]["timedsequences"][index1] = [False,0,0,0] 

266 return() 

267 

268#------------------------------------------------------------------------------------ 

269# Internal Function to Update any signal references when signal ID is changed 

270# Signal 'pointinterlock' comprises: [main, lh1, lh2, rh1, rh2] 

271# Each route comprises: [[p1, p2, p3, p4, p5, p6, p7], sig_id, inst_id] 

272# Note that the sig_id in this case is a string (for local or remote signals) 

273# Signal 'siginterlock' comprises a list of routes [main, lh1, lh2, rh1, rh2] 

274# Each route element comprises a list of signals [sig1, sig2, sig3, sig4] 

275# Each signal element comprises [sig_id, [main, lh1, lh2, rh1, rh2]] 

276# Where each route element is a boolean value (True or False) 

277#------------------------------------------------------------------------------------ 

278 

279def update_references_to_signal(old_sig_id:int, new_sig_id:int): 

280 # Iterate through all the signals on the schematic 

281 for signal_id in objects_common.signal_index: 

282 # Get the Object ID for the signal 

283 sig_object = objects_common.signal(signal_id) 

284 # Update any references for the signal ahead (on the interlocked routes) 

285 # We use strings as the signal ahead IDs support local or remote sections 

286 list_of_interlocked_point_routes = objects_common.schematic_objects[sig_object]["pointinterlock"] 

287 for index1, interlocked_route in enumerate (list_of_interlocked_point_routes): 

288 if interlocked_route[1] == str(old_sig_id): 

289 objects_common.schematic_objects[sig_object]["pointinterlock"][index1][1] = str(new_sig_id) 

290 # Update any references for conflicting signals 

291 list_of_interlocked_signal_routes = objects_common.schematic_objects[sig_object]["siginterlock"] 

292 for index1, interlocked_route in enumerate(list_of_interlocked_signal_routes): 

293 list_of_conflicting_signals = list_of_interlocked_signal_routes[index1] 

294 for index2, conflicting_signal in enumerate(list_of_conflicting_signals): 

295 if conflicting_signal[0] == old_sig_id: 

296 objects_common.schematic_objects[sig_object]["siginterlock"][index1][index2][0] = new_sig_id 

297 # Update any "Trigger Timed signal" references to the signal (either from 

298 # the current signal or another signal on the schematic (ahead of the signal) 

299 list_of_timed_sequences = objects_common.schematic_objects[sig_object]["timedsequences"] 

300 for index1, timed_sequence in enumerate(list_of_timed_sequences): 

301 if timed_sequence[1] == old_sig_id: 

302 objects_common.schematic_objects[sig_object]["timedsequences"][index1][1] = new_sig_id 

303 return() 

304 

305#------------------------------------------------------------------------------------ 

306# Function to remove all references to a point from the signal interlocking tables 

307# Signal 'pointinterlock' comprises a list of routes: [main, lh1, lh2, rh1, rh2] 

308# Each route element comprises: [[p1, p2, p3, p4, p5, p6, p7], sig_id, block_id] 

309# Where sig_id in this case is a string (for local or remote signals) 

310#------------------------------------------------------------------------------------ 

311 

312def remove_references_to_point(point_id:int): 

313 # Iterate through all the signals on the schematic 

314 for signal_id in objects_common.signal_index: 

315 # Get the Object ID of the signal 

316 sig_object = objects_common.signal(signal_id) 

317 # Iterate through each route in the interlocking table 

318 interlocking_table = objects_common.schematic_objects[sig_object]["pointinterlock"] 

319 for index1, interlocked_route in enumerate(interlocking_table): 

320 list_of_interlocked_points = interlocked_route[0] 

321 # Create a new 'blank' list for copying the points (that haven't been deleted) across 

322 # We do this to 'tidy up' the list (i.e. remove the 'blanks' caused by the point removal) 

323 new_list_of_interlocked_points = [[0,False],[0,False],[0,False],[0,False],[0,False],[0,False]] 

324 index2 = 0 

325 # Iterate through each point on the route in the interlocking table 

326 # to build up the new list of points (that are to be retained) 

327 for interlocked_point in list_of_interlocked_points: 

328 if interlocked_point[0] != point_id: 

329 new_list_of_interlocked_points[index2] = interlocked_point 

330 index2 = index2 +1 

331 # Replace the list of interlocked points 

332 objects_common.schematic_objects[sig_object]["pointinterlock"][index1][0]= new_list_of_interlocked_points 

333 return() 

334 

335#------------------------------------------------------------------------------------ 

336# Function to update any references to a Point in the signal interlocking tables 

337#------------------------------------------------------------------------------------ 

338 

339def update_references_to_point(old_point_id:int, new_point_id:int): 

340 # Iterate through all the signals on the schematic 

341 for signal_id in objects_common.signal_index: 

342 # Get the Object ID of the signal 

343 sig_object = objects_common.signal(signal_id) 

344 # Iterate through each route in the interlocking table and then the points on each route 

345 interlocking_table = objects_common.schematic_objects[sig_object]["pointinterlock"] 

346 for index1, interlocked_route in enumerate(interlocking_table): 

347 list_of_interlocked_points = interlocked_route[0] 

348 for index2, interlocked_point in enumerate(list_of_interlocked_points): 

349 if interlocked_point[0] == old_point_id: 

350 objects_common.schematic_objects[sig_object]["pointinterlock"][index1][0][index2][0] = new_point_id 

351 return() 

352 

353#------------------------------------------------------------------------------------ 

354# Function to remove references to a Track Section from the signal automation tables 

355# 'tracksections' is a list of [section_behind, sections_ahead] 

356# where sections_ahead is a list of [MAIN,LH1,LH2,RH1,RH2] 

357#------------------------------------------------------------------------------------ 

358 

359def remove_references_to_section(section_id:int): 

360 # Iterate through all the signals on the schematic 

361 for signal_id in objects_common.signal_index: 

362 # Get the Object ID of the signal 

363 sig_object = objects_common.signal(signal_id) 

364 # Get the table of track sections behind/ahead of the signal 

365 track_sections = objects_common.schematic_objects[sig_object]["tracksections"] 

366 # Check the track section behind the signal 

367 if track_sections[0] == section_id: 

368 track_sections[0] = 0 

369 # Check the track sections in front of the signal 

370 for index1, list_of_sections_ahead in enumerate(track_sections[1]): 

371 for index2, section_ahead in enumerate (list_of_sections_ahead): 

372 if section_ahead == section_id: 

373 objects_common.schematic_objects[sig_object]["tracksections"][1][index1][index2] = 0 

374 # Check the track interlocking table 

375 track_interlocking = objects_common.schematic_objects[sig_object]["trackinterlock"] 

376 for index1, route in enumerate(track_interlocking): 

377 for index2, track_section in enumerate(route): 

378 if track_section == section_id: 

379 objects_common.schematic_objects[sig_object]["trackinterlock"][index1][index2] = 0 

380 return() 

381 

382#------------------------------------------------------------------------------------ 

383# Function to update any references to a Track Section in the signal automation tables 

384#------------------------------------------------------------------------------------ 

385 

386def update_references_to_section(old_section_id:int, new_section_id:int): 

387 # Iterate through all the signals on the schematic 

388 for signal_id in objects_common.signal_index: 

389 # Get the Object ID of the signal 

390 sig_object = objects_common.signal(signal_id) 

391 # Get the table of track sections behind/ahead of the signal 

392 track_sections = objects_common.schematic_objects[sig_object]["tracksections"] 

393 # Check the track section behind the signal 

394 if track_sections[0] == old_section_id: track_sections[0] = new_section_id 

395 # Check the track sections in front of the signal  

396 for index1, list_of_sections_ahead in enumerate(track_sections[1]): 

397 for index2, section_ahead in enumerate (list_of_sections_ahead): 

398 if section_ahead == old_section_id: 

399 objects_common.schematic_objects[sig_object]["tracksections"][1][index1][index2] = new_section_id 

400 # Check the track interlocking table 

401 track_interlocking = objects_common.schematic_objects[sig_object]["trackinterlock"] 

402 for index1, route in enumerate(track_interlocking): 

403 for index2, track_section in enumerate(route): 

404 if track_section == old_section_id: 

405 objects_common.schematic_objects[sig_object]["trackinterlock"][index1][index2] = new_section_id 

406 return() 

407 

408#------------------------------------------------------------------------------------ 

409# Function to remove references to a Block Instrument from the signal interlocking tables 

410# Signal 'pointinterlock' comprises a list of routes: [main, lh1, lh2, rh1, rh2] 

411# Each route element comprises: [[p1, p2, p3, p4, p5, p6, p7], sig_id, block_id] 

412# Where sig_id in this case is a string (for local or remote signals) 

413#------------------------------------------------------------------------------------ 

414 

415def remove_references_to_instrument(inst_id:int): 

416 # Iterate through all the signals on the schematic 

417 for signal_id in objects_common.signal_index: 

418 # Get the Object ID of the signal 

419 sig_object = objects_common.signal(signal_id) 

420 # Iterate through each route in the interlocking table 

421 interlocking_table = objects_common.schematic_objects[sig_object]["pointinterlock"] 

422 for index1, interlocked_route in enumerate(interlocking_table): 

423 if interlocked_route[2] == inst_id: 

424 objects_common.schematic_objects[sig_object]["pointinterlock"][index1][2] = 0 

425 return() 

426 

427#------------------------------------------------------------------------------------ 

428# Function to update any references to a Block Instrument in the signal interlocking tables 

429#------------------------------------------------------------------------------------ 

430 

431def update_references_to_instrument(old_inst_id:int, new_inst_id:int): 

432 # Iterate through all the signals on the schematic 

433 for signal_id in objects_common.signal_index: 

434 # Get the Object ID of the signal 

435 sig_object = objects_common.signal(signal_id) 

436 # Iterate through each route in the interlocking table 

437 interlocking_table = objects_common.schematic_objects[sig_object]["pointinterlock"] 

438 for index, interlocked_route in enumerate (interlocking_table): 

439 if interlocked_route[2] == old_inst_id: 

440 objects_common.schematic_objects[sig_object]["pointinterlock"][index][2] = new_inst_id 

441 return() 

442 

443#------------------------------------------------------------------------------------ 

444# Function to to update a signal object after a configuration change 

445#------------------------------------------------------------------------------------ 

446 

447def update_signal(object_id, new_object_configuration): 

448 # We need to track whether the Item ID has changed 

449 old_item_id = objects_common.schematic_objects[object_id]["itemid"] 

450 new_item_id = new_object_configuration["itemid"] 

451 # Delete the existing signal object, copy across the new configuration and redraw 

452 # Note that the delete_signal_object function will also delete any DCC or sensor mappings 

453 delete_signal_object(object_id) 

454 objects_common.schematic_objects[object_id] = copy.deepcopy(new_object_configuration) 

455 redraw_signal_object(object_id) 

456 # Check to see if the Type-specific ID has been changed 

457 if old_item_id != new_item_id: 

458 # Update the type-specific index 

459 del objects_common.signal_index[str(old_item_id)] 

460 objects_common.signal_index[str(new_item_id)] = object_id 

461 # Update any "signal Ahead" references when signal ID is changed 

462 update_references_to_signal(old_item_id, new_item_id) 

463 # Recalculate point interlocking tables in case they are affected 

464 objects_points.reset_point_interlocking_tables() 

465 return() 

466 

467#------------------------------------------------------------------------------------ 

468# Function to redraw a Signal object on the schematic. Called when the object is first 

469# created or after the object configuration has been updated. 

470#------------------------------------------------------------------------------------ 

471 

472def redraw_signal_object(object_id): 

473 # Turn the signal type value back into the required enumeration type 

474 sig_type = signals_common.sig_type(objects_common.schematic_objects[object_id]["itemtype"]) 

475 # Update the sensor mapping callbacks for the signal (if any have been specified) 

476 if objects_common.schematic_objects[object_id]["passedsensor"][1] != "": 

477 gpio_sensors.add_gpio_sensor_callback(objects_common.schematic_objects[object_id]["passedsensor"][1], 

478 signal_passed = objects_common.schematic_objects[object_id]["itemid"] ) 

479 if objects_common.schematic_objects[object_id]["approachsensor"][1] != "": 

480 gpio_sensors.add_gpio_sensor_callback(objects_common.schematic_objects[object_id]["approachsensor"][1], 

481 signal_approach = objects_common.schematic_objects[object_id]["itemid"] ) 

482 # Create the DCC Mappings for the signal (depending on signal type) 

483 if (sig_type == signals_common.sig_type.colour_light or 

484 sig_type == signals_common.sig_type.ground_position): 

485 # Create the new DCC Mapping for the Colour Light Signal 

486 dcc_control.map_dcc_signal (objects_common.schematic_objects[object_id]["itemid"], 

487 auto_route_inhibit = objects_common.schematic_objects[object_id]["dccautoinhibit"], 

488 proceed = objects_common.schematic_objects[object_id]["dccaspects"][0], 

489 danger = objects_common.schematic_objects[object_id]["dccaspects"][1], 

490 caution = objects_common.schematic_objects[object_id]["dccaspects"][2], 

491 prelim_caution = objects_common.schematic_objects[object_id]["dccaspects"][3], 

492 flash_caution = objects_common.schematic_objects[object_id]["dccaspects"][4], 

493 flash_prelim_caution = objects_common.schematic_objects[object_id]["dccaspects"][5], 

494 NONE = objects_common.schematic_objects[object_id]["dccfeathers"][0], 

495 MAIN = objects_common.schematic_objects[object_id]["dccfeathers"][1], 

496 LH1 = objects_common.schematic_objects[object_id]["dccfeathers"][2], 

497 LH2 = objects_common.schematic_objects[object_id]["dccfeathers"][3], 

498 RH1 = objects_common.schematic_objects[object_id]["dccfeathers"][4], 

499 RH2 = objects_common.schematic_objects[object_id]["dccfeathers"][5], 

500 subsidary = objects_common.schematic_objects[object_id]["subsidary"][1], 

501 THEATRE = objects_common.schematic_objects[object_id]["dcctheatre"] ) 

502 elif (sig_type == signals_common.sig_type.semaphore or 502 ↛ 526line 502 didn't jump to line 526, because the condition on line 502 was never false

503 sig_type == signals_common.sig_type.ground_disc): 

504 # Create the new DCC Mapping for the Semaphore Signal 

505 dcc_control.map_semaphore_signal (objects_common.schematic_objects[object_id]["itemid"], 

506 main_signal = objects_common.schematic_objects[object_id]["sigarms"][0][0][1], 

507 lh1_signal = objects_common.schematic_objects[object_id]["sigarms"][1][0][1], 

508 lh2_signal = objects_common.schematic_objects[object_id]["sigarms"][2][0][1], 

509 rh1_signal = objects_common.schematic_objects[object_id]["sigarms"][3][0][1], 

510 rh2_signal = objects_common.schematic_objects[object_id]["sigarms"][4][0][1], 

511 main_subsidary = objects_common.schematic_objects[object_id]["sigarms"][0][1][1], 

512 lh1_subsidary = objects_common.schematic_objects[object_id]["sigarms"][1][1][1], 

513 lh2_subsidary = objects_common.schematic_objects[object_id]["sigarms"][2][1][1], 

514 rh1_subsidary = objects_common.schematic_objects[object_id]["sigarms"][3][1][1], 

515 rh2_subsidary = objects_common.schematic_objects[object_id]["sigarms"][4][1][1], 

516 THEATRE = objects_common.schematic_objects[object_id]["dcctheatre"] ) 

517 # Create the new DCC Mapping for the associated distant Signal if there is one 

518 if has_associated_distant(object_id): 

519 dcc_control.map_semaphore_signal (objects_common.schematic_objects[object_id]["itemid"]+100, 

520 main_signal = objects_common.schematic_objects[object_id]["sigarms"][0][2][1], 

521 lh1_signal = objects_common.schematic_objects[object_id]["sigarms"][1][2][1], 

522 lh2_signal = objects_common.schematic_objects[object_id]["sigarms"][2][2][1], 

523 rh1_signal = objects_common.schematic_objects[object_id]["sigarms"][3][2][1], 

524 rh2_signal = objects_common.schematic_objects[object_id]["sigarms"][4][2][1] ) 

525 # Create the new signal object (according to the signal type) 

526 if sig_type == signals_common.sig_type.colour_light: 

527 # Turn the signal subtype value back into the required enumeration type 

528 sub_type = signals_colour_lights.signal_sub_type(objects_common.schematic_objects[object_id]["itemsubtype"]) 

529 # Create the signal drawing object on the canvas 

530 signals_colour_lights.create_colour_light_signal ( 

531 canvas = objects_common.canvas, 

532 sig_id = objects_common.schematic_objects[object_id]["itemid"], 

533 x = objects_common.schematic_objects[object_id]["posx"], 

534 y = objects_common.schematic_objects[object_id]["posy"], 

535 signal_subtype = sub_type, 

536 sig_callback = run_layout.schematic_callback, 

537 orientation = objects_common.schematic_objects[object_id]["orientation"], 

538 sig_passed_button = objects_common.schematic_objects[object_id]["passedsensor"][0], 

539 approach_release_button = objects_common.schematic_objects[object_id]["approachsensor"][0], 

540 position_light = objects_common.schematic_objects[object_id]["subsidary"][0], 

541 mainfeather = objects_common.schematic_objects[object_id]["feathers"][0], 

542 lhfeather45 = objects_common.schematic_objects[object_id]["feathers"][1], 

543 lhfeather90 = objects_common.schematic_objects[object_id]["feathers"][2], 

544 rhfeather45 = objects_common.schematic_objects[object_id]["feathers"][3], 

545 rhfeather90 = objects_common.schematic_objects[object_id]["feathers"][4], 

546 theatre_route_indicator = objects_common.schematic_objects[object_id]["theatreroute"], 

547 refresh_immediately = False, 

548 fully_automatic = objects_common.schematic_objects[object_id]["fullyautomatic"]) 

549 # set the initial theatre route indication (for MAIN) for the signal if appropriate 

550 if objects_common.schematic_objects[object_id]["theatreroute"]: 

551 signals.set_route(sig_id = objects_common.schematic_objects[object_id]["itemid"], 

552 theatre_text = objects_common.schematic_objects[object_id]["dcctheatre"][1][0]) 

553 # update the signal to show the initial aspect 

554 signals.update_signal(objects_common.schematic_objects[object_id]["itemid"]) 

555 elif sig_type == signals_common.sig_type.semaphore: 

556 # Turn the signal subtype value back into the required enumeration type 

557 sub_type = signals_semaphores.semaphore_sub_type(objects_common.schematic_objects[object_id]["itemsubtype"]) 

558 # Create the signal drawing object on the canvas. Note that the main signal arm is always enabled for home 

559 # or distant signals - it is only optional for secondary distant signals (created after the main signal) 

560 signals_semaphores.create_semaphore_signal ( 

561 canvas = objects_common.canvas, 

562 sig_id = objects_common.schematic_objects[object_id]["itemid"], 

563 x = objects_common.schematic_objects[object_id]["posx"], 

564 y = objects_common.schematic_objects[object_id]["posy"], 

565 signal_subtype = sub_type, 

566 sig_callback = run_layout.schematic_callback, 

567 orientation = objects_common.schematic_objects[object_id]["orientation"], 

568 sig_passed_button = objects_common.schematic_objects[object_id]["passedsensor"][0], 

569 approach_release_button = objects_common.schematic_objects[object_id]["approachsensor"][0], 

570 main_signal = True, 

571 lh1_signal = objects_common.schematic_objects[object_id]["sigarms"][1][0][0], 

572 lh2_signal = objects_common.schematic_objects[object_id]["sigarms"][2][0][0], 

573 rh1_signal = objects_common.schematic_objects[object_id]["sigarms"][3][0][0], 

574 rh2_signal = objects_common.schematic_objects[object_id]["sigarms"][4][0][0], 

575 main_subsidary = objects_common.schematic_objects[object_id]["sigarms"][0][1][0], 

576 lh1_subsidary = objects_common.schematic_objects[object_id]["sigarms"][1][1][0], 

577 lh2_subsidary = objects_common.schematic_objects[object_id]["sigarms"][2][1][0], 

578 rh1_subsidary = objects_common.schematic_objects[object_id]["sigarms"][3][1][0], 

579 rh2_subsidary = objects_common.schematic_objects[object_id]["sigarms"][4][1][0], 

580 theatre_route_indicator = objects_common.schematic_objects[object_id]["theatreroute"], 

581 fully_automatic = objects_common.schematic_objects[object_id]["fullyautomatic"]) 

582 # Create the associated distant signal (signal_id = home_signal_id + 100) 

583 if has_associated_distant(object_id): 

584 # Create the signal drawing object on the canvas 

585 signals_semaphores.create_semaphore_signal ( 

586 canvas = objects_common.canvas, 

587 sig_id = objects_common.schematic_objects[object_id]["itemid"]+100, 

588 x = objects_common.schematic_objects[object_id]["posx"], 

589 y = objects_common.schematic_objects[object_id]["posy"], 

590 signal_subtype = signals_semaphores.semaphore_sub_type.distant, 

591 associated_home = objects_common.schematic_objects[object_id]["itemid"], 

592 sig_callback = run_layout.schematic_callback, 

593 orientation = objects_common.schematic_objects[object_id]["orientation"], 

594 main_signal = objects_common.schematic_objects[object_id]["sigarms"][0][2][0], 

595 lh1_signal = objects_common.schematic_objects[object_id]["sigarms"][1][2][0], 

596 lh2_signal = objects_common.schematic_objects[object_id]["sigarms"][2][2][0], 

597 rh1_signal = objects_common.schematic_objects[object_id]["sigarms"][3][2][0], 

598 rh2_signal = objects_common.schematic_objects[object_id]["sigarms"][4][2][0], 

599 fully_automatic = objects_common.schematic_objects[object_id]["distautomatic"]) 

600 elif sig_type == signals_common.sig_type.ground_position: 

601 # Turn the signal subtype value back into the required enumeration type 

602 sub_type = signals_ground_position.ground_pos_sub_type(objects_common.schematic_objects[object_id]["itemsubtype"]) 

603 # Create the signal drawing object on the canvas 

604 signals_ground_position.create_ground_position_signal ( 

605 canvas = objects_common.canvas, 

606 sig_id = objects_common.schematic_objects[object_id]["itemid"], 

607 x = objects_common.schematic_objects[object_id]["posx"], 

608 y = objects_common.schematic_objects[object_id]["posy"], 

609 signal_subtype = sub_type, 

610 sig_callback = run_layout.schematic_callback, 

611 orientation = objects_common.schematic_objects[object_id]["orientation"], 

612 sig_passed_button = objects_common.schematic_objects[object_id]["passedsensor"][0]) 

613 elif sig_type == signals_common.sig_type.ground_disc: 613 ↛ 627line 613 didn't jump to line 627, because the condition on line 613 was never false

614 # Turn the signal subtype value back into the required enumeration type 

615 sub_type = signals_ground_disc.ground_disc_sub_type(objects_common.schematic_objects[object_id]["itemsubtype"]) 

616 # Create the signal drawing object on the canvas 

617 signals_ground_disc.create_ground_disc_signal ( 

618 canvas = objects_common.canvas, 

619 sig_id = objects_common.schematic_objects[object_id]["itemid"], 

620 x = objects_common.schematic_objects[object_id]["posx"], 

621 y = objects_common.schematic_objects[object_id]["posy"], 

622 signal_subtype = sub_type, 

623 sig_callback = run_layout.schematic_callback, 

624 orientation = objects_common.schematic_objects[object_id]["orientation"], 

625 sig_passed_button = objects_common.schematic_objects[object_id]["passedsensor"][0]) 

626 # Create/update the canvas "tags" and selection rectangle for the signal 

627 objects_common.schematic_objects[object_id]["tags"] = signals_common.get_tags(objects_common.schematic_objects[object_id]["itemid"]) 

628 objects_common.set_bbox (object_id, objects_common.canvas.bbox(objects_common.schematic_objects[object_id]["tags"])) 

629 return() 

630 

631#------------------------------------------------------------------------------------ 

632# Function to Create a new default signal (and draw it on the canvas) 

633#------------------------------------------------------------------------------------ 

634 

635def create_signal(item_type, item_subtype): 

636 # Generate a new object from the default configuration with a new UUID  

637 object_id = str(uuid.uuid4()) 

638 objects_common.schematic_objects[object_id] = copy.deepcopy(default_signal_object) 

639 # Find the initial canvas position for the new object and assign the item ID 

640 x, y = objects_common.find_initial_canvas_position() 

641 item_id = objects_common.new_item_id(exists_function=signals_common.sig_exists) 

642 # Add the specific elements for this particular instance of the object 

643 objects_common.schematic_objects[object_id]["itemid"] = item_id 

644 objects_common.schematic_objects[object_id]["itemtype"] = item_type 

645 objects_common.schematic_objects[object_id]["itemsubtype"] = item_subtype 

646 objects_common.schematic_objects[object_id]["posx"] = x 

647 objects_common.schematic_objects[object_id]["posy"] = y 

648 # Add the new object to the index of signals 

649 objects_common.signal_index[str(item_id)] = object_id 

650 # Draw the object on the canvas 

651 redraw_signal_object(object_id) 

652 return(object_id) 

653 

654#------------------------------------------------------------------------------------ 

655# Function to paste a copy of an existing signal - returns the new Object ID 

656# Note that only the basic signal configuration is used. Underlying configuration 

657# such as point interlocking, dcc addresses, automation etc is set back to the 

658# default values as it will need to be configured specific to the new signal 

659#------------------------------------------------------------------------------------ 

660 

661def paste_signal(object_to_paste, deltax:int, deltay:int): 

662 # Create a new UUID for the pasted object 

663 new_object_id = str(uuid.uuid4()) 

664 objects_common.schematic_objects[new_object_id] = copy.deepcopy(object_to_paste) 

665 # Assign a new type-specific ID for the object and add to the index 

666 new_id = objects_common.new_item_id(exists_function=signals_common.sig_exists) 

667 objects_common.schematic_objects[new_object_id]["itemid"] = new_id 

668 objects_common.signal_index[str(new_id)] = new_object_id 

669 # Set the position for the "pasted" object (offset from the original position) 

670 objects_common.schematic_objects[new_object_id]["posx"] += deltax 

671 objects_common.schematic_objects[new_object_id]["posy"] += deltay 

672 # Now set the default values for all elements we don't want to copy: 

673 # Enabled routes for the signal (all route definitions are cleared with interlocking) 

674 objects_common.schematic_objects[new_object_id]["sigroutes"] = default_signal_object["sigroutes"] 

675 objects_common.schematic_objects[new_object_id]["subroutes"] = default_signal_object["subroutes"] 

676 # All interlocking elements (will be completely different for the new signal) 

677 objects_common.schematic_objects[new_object_id]["pointinterlock"] = default_signal_object["pointinterlock"] 

678 objects_common.schematic_objects[new_object_id]["trackinterlock"] = default_signal_object["trackinterlock"] 

679 objects_common.schematic_objects[new_object_id]["siginterlock"] = default_signal_object["siginterlock"] 

680 objects_common.schematic_objects[new_object_id]["interlockahead"] = default_signal_object["interlockahead"] 

681 # All DCC Addresses (will be completely different for the new signal) 

682 objects_common.schematic_objects[new_object_id]["dccaspects"] = default_signal_object["dccaspects"] 

683 objects_common.schematic_objects[new_object_id]["dccfeathers"] = default_signal_object["dccfeathers"] 

684 objects_common.schematic_objects[new_object_id]["dcctheatre"] = default_signal_object["dcctheatre"] 

685 # Associated track sensors and sections (will need different GPIO inputs allocating) 

686 objects_common.schematic_objects[new_object_id]["tracksections"] = default_signal_object["tracksections"] 

687 objects_common.schematic_objects[new_object_id]["passedsensor"] = default_signal_object["passedsensor"] 

688 objects_common.schematic_objects[new_object_id]["approachsensor"] = default_signal_object["approachsensor"] 

689 # Any Timed Signal sequences or approach control need to be cleared 

690 objects_common.schematic_objects[new_object_id]["timedsequences"] = default_signal_object["timedsequences"] 

691 objects_common.schematic_objects[new_object_id]["approachcontrol"] = default_signal_object["approachcontrol"] 

692 # Any override selections will need to be cleared (fully automatic selection can be left) 

693 objects_common.schematic_objects[new_object_id]["overrideahead"] = default_signal_object["overrideahead"] 

694 objects_common.schematic_objects[new_object_id]["overridesignal"] = default_signal_object["overridesignal"] 

695 # Any DCC addresses for the semaphore signal arms 

696 for index1,signal_route in enumerate(objects_common.schematic_objects[new_object_id]["sigarms"]): 

697 for index2,signal_arm in enumerate(signal_route): 

698 objects_common.schematic_objects[new_object_id]["sigarms"][index1][index2][1] = 0 

699 # The DCC Address for the subsidary signal 

700 objects_common.schematic_objects[new_object_id]["subsidary"][1] = 0 

701 # Set the Boundary box for the new object to None so it gets created on re-draw 

702 objects_common.schematic_objects[new_object_id]["bbox"] = None 

703 # Create/draw the new object on the canvas 

704 redraw_signal_object(new_object_id) 

705 # No need to update the point interlocking tables as the pasted signal is 

706 # created without any interlocking configuration - so nothing has changed 

707 return(new_object_id) 

708 

709#------------------------------------------------------------------------------------ 

710# Function to "soft delete" the signal object from the canvas together with all 

711# associated dcc mappings and track sensor mappings. Primarily used to delete the 

712# signal in its current configuration prior to re-creating in its new configuration 

713# following a configuration change - also used as part of a hard delete (below) 

714#------------------------------------------------------------------------------------ 

715 

716def delete_signal_object(object_id): 

717 # Delete the signal drawing objects and associated DCC mapping 

718 signals_common.delete_signal(objects_common.schematic_objects[object_id]["itemid"]) 

719 dcc_control.delete_signal_mapping(objects_common.schematic_objects[object_id]["itemid"]) 

720 # Delete the track sensor mappings for the signal (if any) 

721 passed_sensor = objects_common.schematic_objects[object_id]["passedsensor"][1] 

722 approach_sensor = objects_common.schematic_objects[object_id]["approachsensor"][1] 

723 if passed_sensor != "": gpio_sensors.remove_gpio_sensor_callback(passed_sensor) 

724 if approach_sensor != "": gpio_sensors.remove_gpio_sensor_callback(approach_sensor) 

725 # Delete the associated distant signal (if there is one) 

726 if has_associated_distant(object_id): 

727 signals_common.delete_signal(objects_common.schematic_objects[object_id]["itemid"]+100) 

728 dcc_control.delete_signal_mapping(objects_common.schematic_objects[object_id]["itemid"]+100) 

729 return() 

730 

731#------------------------------------------------------------------------------------ 

732# Function to 'hard delete' a signal (drawing objects, DCC mappings, sensor mappings, 

733# and the main dict entry). Function called when signal is deleted from the schematic. 

734#------------------------------------------------------------------------------------ 

735 

736def delete_signal(object_id): 

737 # Soft delete the associated library objects from the canvas 

738 delete_signal_object(object_id) 

739 # Remove any references to the signal from other signals 

740 remove_references_to_signal(objects_common.schematic_objects[object_id]["itemid"]) 

741 # "Hard Delete" the selected object - deleting the boundary box rectangle and deleting 

742 # the object from the dictionary of schematic objects (and associated dictionary keys) 

743 objects_common.canvas.delete(objects_common.schematic_objects[object_id]["bbox"]) 

744 del objects_common.signal_index[str(objects_common.schematic_objects[object_id]["itemid"])] 

745 del objects_common.schematic_objects[object_id] 

746 # Recalculate point interlocking tables to remove references to the signal 

747 objects_points.reset_point_interlocking_tables() 

748 return() 

749 

750#------------------------------------------------------------------------------------ 

751# Function to update the MQTT networking configuration for signals, namely 

752# subscribing to remote signals and setting local signals to publish state 

753# Note that the editor doesn't use signal passed events 

754#------------------------------------------------------------------------------------ 

755 

756def mqtt_update_signals(signals_to_publish:list, signals_to_subscribe_to:list): 

757 signals_common.reset_mqtt_configuration() 

758 signals.set_signals_to_publish_state(*signals_to_publish) 

759 for signal_identifier in signals_to_subscribe_to: 

760 signals.subscribe_to_remote_signal(signal_identifier, run_layout.schematic_callback) 

761 return() 

762 

763####################################################################################