1+ import random
2+ import time
3+
4+ from PyserSSH import Clear
5+ from PyserSSH .extensions .BarPlus import BarPlus_Display , BarPlus_ProgressBar
6+ from PyserSSH .extensions .XHandler import Division
7+ from PyserSSH .extensions .dialog import TextInputDialog , TextDialog
8+ from PyserSSH .extensions .processbar import Steps
9+ from PyserSSH .system .clientype import Client
10+
11+ div = Division ("barplus" , "Test command for bar+ extension module" , category = "Test Function (Bar+)" )
12+
13+ @div .command (name = "barplus" )
14+ def xh_barplus (client : Client ):
15+ running = True
16+
17+ def onkey (key ):
18+ nonlocal running
19+
20+ if key == b"q" :
21+ running = False
22+
23+ Clear (client , only_current_screen = True )
24+
25+ display = BarPlus_Display (client , "BarPlus Test Display" , update_rate = 0.1 )
26+
27+ display .on_key_handle = onkey
28+
29+ display .add_static_line ("Press Q to exit" )
30+ # Create progress bars
31+
32+ # System 13 - Single bar (red)
33+ system13 = BarPlus_ProgressBar ("System 13" , width = 30 )
34+ system13 .add_segment (0 , 500 , "255;0;0" , "Processing" )
35+ system13 .set_info ("" )
36+
37+ # System 14 - Stacked bar with multiple segments
38+ system14 = BarPlus_ProgressBar ("System 14" , width = 30 , steps_animation = Steps .receiving , ena_stack_layer = True )
39+ system14 .add_segment (0 , 200 , "0;255;0" , "Complete" )
40+ system14 .add_segment (0 , 150 , "255;255;0" , "Processing" , layer = 1 )
41+ system14 .add_segment (0 , 100 , "255;0;0" , "Pending" , layer = 2 )
42+ system14 .set_info ("" )
43+
44+ system15 = BarPlus_ProgressBar ("System 15" , width = 30 , steps_animation = Steps .connecting )
45+ system15 .add_segment (0 , 300 , "0;247;247" , "Base" ) # Base layer
46+ system15 .add_segment (0 , 200 , "255;255;0" , "Buffer" ) # Buffer layer (can override base)
47+ system15 .add_segment (0 , 100 , "255;0;0" , "Current" ) # Current layer (highest priority)
48+ system15 .set_info ("" )
49+
50+ # System 15 - Different colors
51+ system16 = BarPlus_ProgressBar ("System 16" , width = 30 , steps_animation = Steps .requesting )
52+ system16 .add_segment (0 , 300 , "0;247;247" , "Active" )
53+ system16 .add_segment (0 , 100 , "247;0;247" , "Queue" )
54+ system16 .set_info ("" )
55+
56+ # System 16 - Small bar (blue)
57+ system17 = BarPlus_ProgressBar ("System 17" , width = 30 , steps_animation = Steps .waiting )
58+ system17 .add_segment (0 , 150 , "0;0;255" , "Tasks" )
59+ system17 .set_info ("" )
60+
61+ # Add bars to display
62+ display .add_progress_bar (system13 )
63+ display .add_progress_bar (system14 )
64+ display .add_progress_bar (system15 )
65+ display .add_progress_bar (system16 )
66+ display .add_progress_bar (system17 )
67+
68+ display .start ()
69+
70+ step = 0
71+ while True :
72+ # Update System 13
73+ system13 .update_segment (0 , min (step * 2 , 500 ))
74+
75+ # Update System 14 (stacked)
76+ system14 .update_segment (0 , min (step * 1 , 200 )) # Complete
77+ system14 .update_segment (1 , min (step * 1 , 150 )) # Processing
78+ system14 .update_segment (2 , min (step * 1 , 100 )) # Pending
79+
80+ # Update System 15 (stacked)
81+ system16 .update_segment (0 , min (step * 4 , 300 )) # Active
82+ system16 .update_segment (1 , min (step * 1 , 100 )) # Queue
83+
84+ system15 .update_segment (0 , min (step * 4 , 300 )) # Base (cyan)
85+ system15 .update_segment (1 , min (step * 3 , 200 )) # Buffer (yellow) - overrides cyan
86+ system15 .update_segment (2 , min (step * 2 , 100 )) # Current (red) - overrides everything
87+
88+ # Update System 16
89+ system17 .update_segment (0 , min (step * 3 , 150 ))
90+
91+ time .sleep (0.01 )
92+ step += 1
93+
94+ if step > 250 or not running : # Reset after completion
95+ system13 .stop ()
96+ system14 .stopfail ()
97+ system15 .stop ()
98+ system16 .stopfail ()
99+ system17 .stop ()
100+
101+ time .sleep (0.1 )
102+
103+ display .exit ()
104+ break
105+
106+ class PID :
107+ def __init__ (self , kp , ki , kd ):
108+ self .kp = kp
109+ self .ki = ki
110+ self .kd = kd
111+ self .prev_error = 0
112+ self .integral = 0
113+
114+ def compute (self , target , actual ):
115+ error = target - actual
116+ self .integral += error
117+ derivative = error - self .prev_error
118+ output = self .kp * error + self .ki * self .integral + self .kd * derivative
119+ self .prev_error = error
120+ return output
121+
122+ @div .command (name = "engpid" )
123+ def xh_engpid (client : Client ):
124+ running = True
125+ max_rpm = 7000
126+ target_rpm = 3000
127+
128+ display = BarPlus_Display (client , "Engine RPM Controller" , update_rate = 0.1 )
129+ pid = PID (kp = 0.004 , ki = 0.003 , kd = 0.0 )
130+
131+ def onkey (key ):
132+ nonlocal running , target_rpm
133+
134+ if key == b"q" :
135+ running = False
136+ elif key == b"w" :
137+ target_rpm = min (target_rpm + 100 , max_rpm )
138+ rpm_bar .update_segment (1 , int (target_rpm ))
139+ elif key == b"s" :
140+ target_rpm = max (target_rpm - 100 , 0 )
141+ rpm_bar .update_segment (1 , int (target_rpm ))
142+ elif key == b"p" :
143+ display .is_paused = True
144+ DiR = TextInputDialog (client , "PID Settings" , "Enter new Kp value (Float Number)" )
145+ DiR .render ()
146+ try :
147+ pid .kp = float (DiR .output ())
148+ Dii = TextDialog (client , f"New Kp value set to { pid .kp } " , "PID Settings" , exit_key = None )
149+ Dii .render ()
150+ except :
151+ Dii = TextDialog (client , "Invalid input. Please enter a valid float number." , "PID Settings" , exit_key = None )
152+ Dii .render ()
153+ display .is_paused = False
154+ elif key == b"i" :
155+ display .is_paused = True
156+ DiR = TextInputDialog (client , "PID Settings" , "Enter new Ki value (Float Number)" )
157+ DiR .render ()
158+ try :
159+ pid .ki = float (DiR .output ())
160+ Dii = TextDialog (client , f"New Ki value set to { pid .ki } " , "PID Settings" , exit_key = None )
161+ Dii .render ()
162+ except :
163+ Dii = TextDialog (client , "Invalid input. Please enter a valid float number." , "PID Settings" , exit_key = None )
164+ Dii .render ()
165+ display .is_paused = False
166+ elif key == b"d" :
167+ display .is_paused = True
168+ DiR = TextInputDialog (client , "PID Settings" , "Enter new Kd value (Float Number)" )
169+ DiR .render ()
170+ try :
171+ pid .kd = float (DiR .output ())
172+ Dii = TextDialog (client , f"New Kd value set to { pid .kd } " , "PID Settings" , exit_key = None )
173+ Dii .render ()
174+ except :
175+ Dii = TextDialog (client , "Invalid input. Please enter a valid float number." , "PID Settings" , exit_key = None )
176+ Dii .render ()
177+ display .is_paused = False
178+
179+ Clear (client , only_current_screen = True )
180+
181+ display .on_key_handle = onkey
182+
183+ display .add_static_line ("Press Q to exit, W to increase target RPM, S to decrease target RPM" )
184+ display .add_static_line ("Press P to change Kp, I to change Ki, D to change Kd" )
185+
186+ rpm_bar = BarPlus_ProgressBar ("RPM (Revving)" , width = 40 , steps_animation = Steps .requesting , ena_stack_layer = True )
187+
188+ rpm_bar .add_segment (0 , max_rpm , "255;0;0" , "Current RPM" )
189+ rpm_bar .add_segment (0 , max_rpm , "255;255;0" , "Target RPM" , layer = 1 )
190+
191+ rpm_bar .set_info ("" )
192+ display .add_progress_bar (rpm_bar )
193+
194+ actual_rpm = 0
195+ throttle = 0
196+
197+ rpm_bar .update_segment (1 , int (target_rpm ))
198+
199+ display .start ()
200+
201+ while True :
202+ # PID logic
203+ correction = pid .compute (target_rpm , actual_rpm )
204+ throttle += correction
205+ throttle = max (0 , min (100 , throttle ))
206+
207+ # Simulate engine RPM + noise
208+ rpm_change = throttle * 80
209+ noise = random .uniform (- 150 , 150 )
210+ actual_rpm = rpm_change + noise
211+ actual_rpm = max (0 , min (max_rpm , actual_rpm ))
212+
213+ # Update progress bar
214+ rpm_bar .update_segment (0 , int (actual_rpm ))
215+
216+ time .sleep (0.01 )
217+
218+ if not running : # Reset after completion
219+ display .exit ()
220+ break
0 commit comments