Skip to content

Commit 98d1a23

Browse files
power off button enable/disable
1 parent 28e7c51 commit 98d1a23

File tree

5 files changed

+71
-23
lines changed

5 files changed

+71
-23
lines changed
2.19 KB
Binary file not shown.
1.69 KB
Binary file not shown.

ups2_GUI.py

+42-12
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,22 @@
11
# -*- coding: utf-8 -*-
2+
"""
3+
Graphical interface for UPS-2 UART serial mode.
4+
5+
Usage:
6+
* For autostart: put this script in /etc/xdg/lxsession/LXDE-pi/autostart
7+
* This script needs PySimpleGUI.py found on https://github.com/PySimpleGUI/PySimpleGUI
8+
* Raspberry serial interface must be enabled (with raspi-config) i.e.
9+
* ups2_serial.py worker service must be started (instructions see docstring)
10+
"""
11+
#Todo: abs
12+
# calendar timed functions
13+
# email and/or other messaging functions
14+
215
import PySimpleGUI as sg
316
import os
417
import ups2_Interface as ups
518

6-
"""
7-
#for autostart: put this script in /etc/xdg/lxsession/LXDE-pi/autostart
8-
"""
19+
920

1021
print('PySimpleGUI Version', sg.version)
1122

@@ -14,7 +25,6 @@
1425
ser = ups.ecInitSerial()
1526
fT = open("/sys/class/thermal/thermal_zone0/temp", "r") #Pi processor temperature
1627

17-
1828
#globals
1929
bgOFF = 'lightgrey'
2030
bgOK = '#A2C477'
@@ -28,7 +38,13 @@
2838
keyPiCPU = 'K_PI_T'
2939

3040
def ecPopWin(count, title = 'ECOM UPS2'):
31-
#Open a modal popup for count seconds and return 'shutdown' or 'cancel'
41+
'''Opens a modal popup for count seconds and returns "shutdown" or "cancel"
42+
43+
Args:
44+
param count: countdown time in seconds
45+
param title: String to display in popup banner
46+
47+
'''
3248

3349
devider = count * 10
3450
layout2 = [[sg.Text('Pi shuddown in'),
@@ -59,7 +75,16 @@ def ecPopWin(count, title = 'ECOM UPS2'):
5975

6076

6177
def ecFormatDisplay(sysStatus, window):
62-
#Set display attributes according to system state
78+
'''Set display attributes according to system state.
79+
80+
This function refreshes the display depending on the system state
81+
Must be periodically called by the main control loop
82+
83+
Args:
84+
sysStatus: string received from UPS-2 hardware
85+
window: initialized main window
86+
'''
87+
6388
s = int(sysStatus, 16) #sysStatus comes as string
6489

6590
#default values. In dictionary in order to easily update depending on status
@@ -81,7 +106,7 @@ def ecFormatDisplay(sysStatus, window):
81106
if s & 0x0020: #batt V present
82107
battState.update(bgColor = bgOK, stat = 'OK')
83108
if s & 0x0040: #usb V present
84-
usbState.update(bgColor = bgOK, text = 'active')
109+
usbState.update(bgColor = bgOK, text = 'active')
85110
if (s & 0x0110) == 0x0110: #main V LOW
86111
mainState.update(stat = 'LOW', bgColor = bgLOW)
87112
if s & 0x0200: #main V HIGH
@@ -92,9 +117,8 @@ def ecFormatDisplay(sysStatus, window):
92117
battState.update(stat = 'HIGH', bgColor = bgHIGH)
93118
if s & 0x1000: #CPU temp HIGH
94119
battState.update(stat = 'HIGH', bgColor = bgHIGH)
95-
96120

97-
#adapt elements
121+
#adapt value displays
98122
window['K_MAIN_V'].update(background_color = mainState['bgColor'])
99123
window['K_MAIN_V'].Widget.configure(borderwidth = mainState['borderW']) #use underlying element
100124
window['K_MAIN_STATE'].update(mainState['stat'])
@@ -103,9 +127,15 @@ def ecFormatDisplay(sysStatus, window):
103127
window['K_BATT_STATE'].update(battState['stat'])
104128
window['K_USB'].update(background_color = usbState['bgColor'])
105129
window['K_USB'].update(usbState['text'])
130+
#adapt power button
106131

107-
108-
132+
if s & 0x0004:
133+
# window['Power OFF'].set_tooltip('Disabled, if USB 5V supplied')
134+
window['Power OFF'].update(disabled=True, disabled_button_color=('lightgrey', 'none'))
135+
136+
else:
137+
window['Power OFF'].update(disabled=False)
138+
# window['Power OFF'].SetTooltip('')
109139

110140
# Main window column layout
111141
col1 = [[sg.Text(text='Main supply', key="K_MAIN_LBL", size=(10,0), justification='right')],
@@ -130,7 +160,7 @@ def ecFormatDisplay(sysStatus, window):
130160
mainFrame = [[ sg.Column(col1), sg.Column(col2), sg.Column(col3), sg.Column(col4), sg.Column(col5)]]
131161

132162
#buttons to appear in frame below
133-
keypanel = [[sg.Button('Power OFF'), sg.Button('Restart'), sg.Button('Standby'), sg.Button('Quit')]]
163+
keypanel = [[sg.Button('Power OFF', tooltip='Disabled if USB powered'), sg.Button('Restart'), sg.Button('Standby'), sg.Button('Quit')]]
134164

135165
#frame layout around buttons
136166
layout = [[sg.Frame('Power Supply Overview', mainFrame)],

ups2_Interface.py

+15-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
1+
"""Module containimg functions for serial communication with UPS-2 power supply.
2+
3+
Module ups2_serial.py must be active in background.
4+
"""
5+
16
import serial
27
import fcntl
38

49
def ecInitSerial(device = '/dev/serial0'):
10+
'''Opens serial device and returns a handle to to the device'''
11+
12+
513
ser = serial.Serial(
614
port= device,
715
baudrate = 38400,
@@ -15,7 +23,7 @@ def ecInitSerial(device = '/dev/serial0'):
1523
return ser
1624

1725
def ecReadline(ser):
18-
"""Returns a string from serial line until a '\n' chahacter"""
26+
"""Returns a string from serial line until a <CR> character."""
1927
rxLine = ""
2028
charCount = 0
2129
while True:
@@ -28,8 +36,9 @@ def ecReadline(ser):
2836
charCount +=1
2937
rxLine +=rxChar.decode("ascii")
3038

31-
def ecFormatAnalog(analogStr = '0.0,0.0.25'):
32-
### format 'main,batt,temp' into list ###
39+
def ecFormatAnalog(analogStr):
40+
'''Add units to analogStr 'main,batt,temp' and return as a list.'''
41+
3342
units = ('V ','V ','°C')
3443
l = []
3544
v = analogStr.split(',')
@@ -38,6 +47,7 @@ def ecFormatAnalog(analogStr = '0.0,0.0.25'):
3847
return l
3948

4049
def ecGetUPSValues(ser):
50+
'''Requests values from UPS-2 by serial interface service ups2_serial.py.'''
4151
try:
4252
request = "r?status\n"
4353
fcntl.flock(ser, fcntl.LOCK_EX)
@@ -58,6 +68,8 @@ def ecGetUPSValues(ser):
5868
pass
5969

6070
def ecReqUPSPowerDown(ser):
71+
'''Initiates a Pi shutdown and executes power off after Pi is down'''
72+
6173
ack =''
6274
try:
6375
request = "r?shutdown -P\n"
@@ -70,4 +82,3 @@ def ecReqUPSPowerDown(ser):
7082
except:
7183
print("exception happended @ ecReqUPSPowerDown()")
7284
pass
73-

ups2_serial.py

+14-7
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
1-
#worker service, to call in /etc/rc.local
1+
"""
2+
Place a call to this service in /etc/rc.local:
3+
python3 /path/to/ups2_serial.py &
4+
"""
5+
26
import serial
37
import time
48
import sys
59
import os
610
import fcntl
711

812
def ecReadline(ser):
9-
"""Returns a string from serial line until a '\n' chahacter"""
13+
"""Returns a string from serial line until a <CR> chahacter."""
1014
rxLine = ""
1115
charCount = 0
1216
while True:
@@ -22,17 +26,18 @@ def ecReadline(ser):
2226

2327

2428
def ecExecSerCommand(rxLine):
25-
"""check if command from UPS"""
29+
"""Check if command comes from UPS and execute."""
2630
command = "--"
2731
#linux system commands from UPS
2832
if rxLine[0:2] == "u!": #prefix
2933
command = rxLine[2:]
3034
command = "sudo " + command
35+
#acknowledge before executing shutdown
3136
ackString = ">OK " + command + "\n"
3237
ser.write(str(ackString).encode())
3338
time.sleep(1) #give UPS a chance to read the ack String
3439
# ser.send_break(1000.0)
35-
os.system(str(command).encode())
40+
os.system(str(command).encode()) #this will normally execute a shutdown command
3641

3742
else:
3843
if rxLine[0:2] == "u?":
@@ -43,13 +48,12 @@ def ecExecSerCommand(rxLine):
4348
print("Command = " + command)
4449
return ""
4550

46-
4751

4852
# os.system(command)
49-
5053

5154
if __name__ == "__main__":
5255
#ser = serial.Serial('/dev/serial0', 38400, timeout = 1) # ttyACM1 for Arduino board
56+
""" This service handles serial communication with ECOM UPS-2 power supply. """
5357
ser = serial.Serial(
5458
port='/dev/serial0',
5559
baudrate = 38400,
@@ -76,17 +80,20 @@ def ecExecSerCommand(rxLine):
7680
charCount = 0
7781
while True:
7882
try:
83+
#lock serial interface in order to prevent interfering by other tasks
7984
fcntl.flock(ser, fcntl.LOCK_EX)
8085
rxLine = ecReadline(ser)
8186
# fcntl.flock(ser, fcntl.LOCK_UN)
8287
rxLine = ecExecSerCommand(rxLine)
88+
#unlock interface after processing rx data
8389
fcntl.flock(ser, fcntl.LOCK_UN)
8490
time.sleep(1.5) ##allow serial port by other process
8591
rxLine +=rxChar.decode("ascii")
8692
except:
8793
pass
8894
print ("Restart")
89-
ser.flush() #flush the buffer
95+
#following code should never be executed
96+
ser.flush() #clean up
9097
ser.close()
9198

9299

0 commit comments

Comments
 (0)