Coverage for /home/pi/Software/model-railway-signalling/model_railway_signals/library/signals_ground_disc.py: 84%

67 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2024-04-05 17:29 +0100

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

2# This module is used for creating and managing Ground disc signal objects 

3# -------------------------------------------------------------------------------- 

4 

5from . import signals_common 

6from . import dcc_control 

7from . import file_interface 

8from . import common 

9 

10import logging 

11import enum 

12 

13# ------------------------------------------------------------------------- 

14# Classes used externally when creating/updating Ground Disk signals  

15# ------------------------------------------------------------------------- 

16 

17# Define the superset of signal sub types that can be created 

18class ground_disc_sub_type(enum.Enum): 

19 standard = 1 

20 shunt_ahead = 2 

21 

22# ------------------------------------------------------------------------- 

23# Public API function to create a Ground Disc Signal (drawing objects and 

24# internal state). By default the Signal is "NOT CLEAR" (i.e. set to DANGER) 

25# ------------------------------------------------------------------------- 

26 

27def create_ground_disc_signal (canvas, sig_id:int, x:int, y:int, 

28 signal_subtype=ground_disc_sub_type.standard, 

29 sig_callback = None, 

30 orientation:int = 0, 

31 sig_passed_button: bool = False): 

32 logging.info ("Signal "+str(sig_id)+": Creating Ground Disc Signal") 

33 # Do some basic validation on the parameters we have been given 

34 if signals_common.sig_exists(sig_id): 34 ↛ 35line 34 didn't jump to line 35, because the condition on line 34 was never true

35 logging.error ("Signal "+str(sig_id)+": Signal already exists") 

36 elif sig_id < 1: 36 ↛ 37line 36 didn't jump to line 37, because the condition on line 36 was never true

37 logging.error ("Signal "+str(sig_id)+": Signal ID must be greater than zero") 

38 elif orientation != 0 and orientation != 180: 38 ↛ 39line 38 didn't jump to line 39, because the condition on line 38 was never true

39 logging.error ("Signal "+str(sig_id)+": Invalid orientation angle - only 0 and 180 currently supported") 

40 else: 

41 # Define the "Tag" for all drawing objects for this signal instance 

42 sig_id_tag = "signal"+str(sig_id) 

43 # Draw the signal base 

44 line_coords = common.rotate_line (x,y,0,0,0,-11,orientation) 

45 canvas.create_line (line_coords,width=2,tags=sig_id_tag) 

46 line_coords = common.rotate_line (x,y,0,-11,5,-11,orientation) 

47 canvas.create_line (line_coords,width=2,tags=sig_id_tag) 

48 # Draw the White disc of the signal 

49 oval_coords = common.rotate_line (x,y,+5,-21,+21,-5,orientation) 

50 canvas.create_oval(oval_coords,fill="white",outline="black",tags=sig_id_tag) 

51 # Draw the banner arms for the signal 

52 if signal_subtype == ground_disc_sub_type.shunt_ahead: arm_colour="yellow3" 

53 else: arm_colour = "red" 

54 line_coords = common.rotate_line(x,y,+13,-21,+13,-5,orientation) 

55 sigon = canvas.create_line(line_coords,fill=arm_colour,width=3,tags=sig_id_tag) 

56 line_coords = common.rotate_line(x,y,+18,-19,+8,-7,orientation) 

57 sigoff = canvas.create_line(line_coords,fill=arm_colour,width=3,tags=sig_id_tag) 

58 

59 # Create all of the signal elements common to all signal types 

60 signals_common.create_common_signal_elements (canvas, sig_id, x, y, 

61 signal_type = signals_common.sig_type.ground_disc, 

62 ext_callback = sig_callback, 

63 orientation = orientation, 

64 sig_passed_button = sig_passed_button, 

65 tag = sig_id_tag) 

66 

67 # Add all of the signal-specific elements we need to manage Ground Position light signal types 

68 signals_common.signals[str(sig_id)]["sig_subtype"] = signal_subtype # Type-specific - signal subtype 

69 signals_common.signals[str(sig_id)]["sigon"] = sigon # Type-specific - drawing object 

70 signals_common.signals[str(sig_id)]["sigoff"] = sigoff # Type-specific - drawing object 

71 

72 # Get the initial state for the signal (if layout state has been successfully loaded) 

73 # Note that each element of 'loaded_state' will be 'None' if no data was loaded 

74 loaded_state = file_interface.get_initial_item_state("signals",sig_id) 

75 # Set the initial state from the "loaded" state - We only need to set the 'override' and 

76 # 'sigclear' for ground signals - everything else gets set when the signal is updated 

77 if loaded_state["override"]: signals_common.set_signal_override(sig_id) 

78 if loaded_state["sigclear"]: signals_common.toggle_signal(sig_id) 

79 # Update the signal to show the initial aspect (and send out DCC commands) 

80 update_ground_disc_signal(sig_id) 

81 # finally Lock the signal if required 

82 if loaded_state["siglocked"]: signals_common.lock_signal(sig_id) 

83 # Publish the initial state to the broker (for other nodes to consume). Note that changes will 

84 # only be published if the MQTT interface has been configured for publishing updates for this  

85 # signal. This allows publish/subscribe to be configured prior to signal creation 

86 signals_common.publish_signal_state(sig_id) 

87 return () 

88 

89# ------------------------------------------------------------------------- 

90# Internal function to Refresh the aspects of a ground disc signal 

91# Note that we expect this function to only ever get called on a state  

92# change therefore we don't track the displayed aspect of the signal 

93# ------------------------------------------------------------------------- 

94 

95def update_ground_disc_signal (sig_id:int): 

96 

97 # Establish what the signal should be displaying based on the state 

98 if not signals_common.signals[str(sig_id)]["sigclear"]: 

99 if signals_common.signals[str(sig_id)]["sig_subtype"] == ground_disc_sub_type.shunt_ahead: 

100 aspect_to_set = signals_common.signal_state_type.CAUTION 

101 else: 

102 aspect_to_set = signals_common.signal_state_type.DANGER 

103 log_message = " (signal is ON)" 

104 elif signals_common.signals[str(sig_id)]["override"]: 104 ↛ 105line 104 didn't jump to line 105, because the condition on line 104 was never true

105 if signals_common.signals[str(sig_id)]["sig_subtype"] == ground_disc_sub_type.shunt_ahead: 

106 aspect_to_set = signals_common.signal_state_type.CAUTION 

107 else: 

108 aspect_to_set = signals_common.signal_state_type.DANGER 

109 log_message = " (signal is OVERRIDDEN)" 

110 else: 

111 aspect_to_set = signals_common.signal_state_type.PROCEED 

112 log_message = " (signal is OFF)" 

113 

114 # Only refresh the signal if the aspect has been changed 

115 if aspect_to_set != signals_common.signals[str(sig_id)]["sigstate"]: 

116 logging.info ("Signal "+str(sig_id)+": Changing aspect to " + str(aspect_to_set).rpartition('.')[-1] + log_message) 

117 signals_common.signals[str(sig_id)]["sigstate"] = aspect_to_set 

118 

119 if signals_common.signals[str(sig_id)]["sigstate"] == signals_common.signal_state_type.PROCEED: 

120 signals_common.signals[str(sig_id)]["canvas"].itemconfigure(signals_common.signals[str(sig_id)]["sigoff"],state='normal') 

121 signals_common.signals[str(sig_id)]["canvas"].itemconfigure(signals_common.signals[str(sig_id)]["sigon"],state='hidden') 

122 dcc_control.update_dcc_signal_element(sig_id,True,element="main_signal") 

123 

124 elif ( signals_common.signals[str(sig_id)]["sigstate"] == signals_common.signal_state_type.DANGER or 124 ↛ 132line 124 didn't jump to line 132, because the condition on line 124 was never false

125 signals_common.signals[str(sig_id)]["sigstate"] == signals_common.signal_state_type.CAUTION ): 

126 signals_common.signals[str(sig_id)]["canvas"].itemconfigure(signals_common.signals[str(sig_id)]["sigoff"],state='hidden') 

127 signals_common.signals[str(sig_id)]["canvas"].itemconfigure(signals_common.signals[str(sig_id)]["sigon"],state='normal') 

128 dcc_control.update_dcc_signal_element(sig_id,False,element="main_signal") 

129 

130 # Publish the signal changes to the broker (for other nodes to consume). Note that state changes will only 

131 # be published if the MQTT interface has been successfully configured for publishing updates for this signal 

132 signals_common.publish_signal_state(sig_id) 

133 

134 return () 

135 

136 

137###############################################################################