new upstream 2.8.0
This commit is contained in:
parent
fc7f4b43c1
commit
b2b0c9995a
836 changed files with 137090 additions and 30018 deletions
|
|
@ -1,11 +1,24 @@
|
|||
# Network UPS Tools: data/html
|
||||
|
||||
EXTRA_DIST_PY2GTK2 = \
|
||||
app/ui/gui-1.3.glade \
|
||||
app/NUT-Monitor-py2gtk2.in \
|
||||
app/nut-monitor-py2gtk2.desktop
|
||||
|
||||
EXTRA_DIST_PY3QT5 = \
|
||||
app/ui/aboutdialog1.ui \
|
||||
app/ui/dialog1.ui \
|
||||
app/ui/dialog2.ui \
|
||||
app/ui/window1.ui \
|
||||
app/NUT-Monitor-py3qt5.in \
|
||||
app/nut-monitor-py3qt5.desktop
|
||||
|
||||
EXTRA_DIST = README \
|
||||
app/gui-1.3.glade \
|
||||
app/NUT-Monitor \
|
||||
app/nut-monitor.appdata.xml \
|
||||
app/nut-monitor.desktop \
|
||||
app/nut-monitor.png \
|
||||
app/icons/48x48/nut-monitor.png \
|
||||
app/icons/64x64/nut-monitor.png \
|
||||
app/icons/256x256/nut-monitor.png \
|
||||
app/icons/scalable/nut-monitor.svg \
|
||||
app/README \
|
||||
app/pixmaps/var-rw.png \
|
||||
app/pixmaps/on_line.png \
|
||||
|
|
@ -14,6 +27,14 @@ EXTRA_DIST = README \
|
|||
app/pixmaps/var-ro.png \
|
||||
app/locale/fr/LC_MESSAGES/NUT-Monitor.mo \
|
||||
app/locale/it/LC_MESSAGES/NUT-Monitor.mo \
|
||||
module/PyNUT.py \
|
||||
module/test_nutclient.py
|
||||
module/PyNUT.py.in \
|
||||
module/test_nutclient.py.in
|
||||
|
||||
# TODO: Make py2/py3-only builds, delivered preferred symlinks, etc. optional:
|
||||
EXTRA_DIST += $(EXTRA_DIST_PY2GTK2)
|
||||
EXTRA_DIST += $(EXTRA_DIST_PY3QT5)
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in .dirstamp
|
||||
|
||||
clean-local:
|
||||
rm -rf *.pyc __pycache__ */*.pyc */__pycache__ */*/*.pyc */*/__pycache__
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# Makefile.in generated by automake 1.14.1 from Makefile.am.
|
||||
# Makefile.in generated by automake 1.16.3 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994-2013 Free Software Foundation, Inc.
|
||||
# Copyright (C) 1994-2020 Free Software Foundation, Inc.
|
||||
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
|
|
@ -16,7 +16,17 @@
|
|||
|
||||
# Network UPS Tools: data/html
|
||||
VPATH = @srcdir@
|
||||
am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
|
||||
am__is_gnu_make = { \
|
||||
if test -z '$(MAKELEVEL)'; then \
|
||||
false; \
|
||||
elif test -n '$(MAKE_HOST)'; then \
|
||||
true; \
|
||||
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
|
||||
true; \
|
||||
else \
|
||||
false; \
|
||||
fi; \
|
||||
}
|
||||
am__make_running_with_option = \
|
||||
case $${target_option-} in \
|
||||
?) ;; \
|
||||
|
|
@ -81,18 +91,24 @@ build_triplet = @build@
|
|||
host_triplet = @host@
|
||||
target_triplet = @target@
|
||||
subdir = scripts/python
|
||||
DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am README
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_compare_version.m4 \
|
||||
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \
|
||||
$(top_srcdir)/m4/ax_c_pragmas.m4 \
|
||||
$(top_srcdir)/m4/ax_check_compile_flag.m4 \
|
||||
$(top_srcdir)/m4/ax_compare_version.m4 \
|
||||
$(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \
|
||||
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
|
||||
$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
|
||||
$(top_srcdir)/m4/lt~obsolete.m4 \
|
||||
$(top_srcdir)/m4/nut_arg_with.m4 \
|
||||
$(top_srcdir)/m4/nut_check_asciidoc.m4 \
|
||||
$(top_srcdir)/m4/nut_check_cppcheck.m4 \
|
||||
$(top_srcdir)/m4/nut_check_headers_windows.m4 \
|
||||
$(top_srcdir)/m4/nut_check_libavahi.m4 \
|
||||
$(top_srcdir)/m4/nut_check_libfreeipmi.m4 \
|
||||
$(top_srcdir)/m4/nut_check_libgd.m4 \
|
||||
$(top_srcdir)/m4/nut_check_libltdl.m4 \
|
||||
$(top_srcdir)/m4/nut_check_libmodbus.m4 \
|
||||
$(top_srcdir)/m4/nut_check_libneon.m4 \
|
||||
$(top_srcdir)/m4/nut_check_libnetsnmp.m4 \
|
||||
$(top_srcdir)/m4/nut_check_libnss.m4 \
|
||||
|
|
@ -101,11 +117,17 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_compare_version.m4 \
|
|||
$(top_srcdir)/m4/nut_check_libusb.m4 \
|
||||
$(top_srcdir)/m4/nut_check_libwrap.m4 \
|
||||
$(top_srcdir)/m4/nut_check_os.m4 \
|
||||
$(top_srcdir)/m4/nut_check_pkgconfig.m4 \
|
||||
$(top_srcdir)/m4/nut_check_python.m4 \
|
||||
$(top_srcdir)/m4/nut_compiler_family.m4 \
|
||||
$(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \
|
||||
$(top_srcdir)/m4/nut_report_feature.m4 \
|
||||
$(top_srcdir)/m4/nut_stash_warnings.m4 \
|
||||
$(top_srcdir)/m4/nut_type_socklen_t.m4 \
|
||||
$(top_srcdir)/configure.ac
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
|
||||
mkinstalldirs = $(install_sh) -d
|
||||
CONFIG_HEADER = $(top_builddir)/include/config.h
|
||||
CONFIG_CLEAN_FILES =
|
||||
|
|
@ -130,6 +152,7 @@ am__can_run_installinfo = \
|
|||
*) (install-info --version) >/dev/null 2>&1;; \
|
||||
esac
|
||||
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
|
||||
am__DIST_COMMON = $(srcdir)/Makefile.in README
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
A2X = @A2X@
|
||||
ACLOCAL = @ACLOCAL@
|
||||
|
|
@ -138,6 +161,7 @@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
|
|||
AR = @AR@
|
||||
ASCIIDOC = @ASCIIDOC@
|
||||
ASPELL = @ASPELL@
|
||||
AUGPARSE = @AUGPARSE@
|
||||
AUTOCONF = @AUTOCONF@
|
||||
AUTOHEADER = @AUTOHEADER@
|
||||
AUTOMAKE = @AUTOMAKE@
|
||||
|
|
@ -148,6 +172,7 @@ CCDEPMODE = @CCDEPMODE@
|
|||
CFLAGS = @CFLAGS@
|
||||
CONFPATH = @CONFPATH@
|
||||
CPP = @CPP@
|
||||
CPPCHECK = @CPPCHECK@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@
|
||||
CPPUNIT_LIBS = @CPPUNIT_LIBS@
|
||||
|
|
@ -161,6 +186,7 @@ DEFS = @DEFS@
|
|||
DEPDIR = @DEPDIR@
|
||||
DLLTOOL = @DLLTOOL@
|
||||
DOC_BUILD_LIST = @DOC_BUILD_LIST@
|
||||
DOC_CHECK_LIST = @DOC_CHECK_LIST@
|
||||
DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@
|
||||
DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@
|
||||
DRIVER_MAN_LIST = @DRIVER_MAN_LIST@
|
||||
|
|
@ -173,6 +199,7 @@ ECHO_T = @ECHO_T@
|
|||
EGREP = @EGREP@
|
||||
EXEEXT = @EXEEXT@
|
||||
FGREP = @FGREP@
|
||||
GDLIB_CONFIG = @GDLIB_CONFIG@
|
||||
GREP = @GREP@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
|
|
@ -190,6 +217,8 @@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@
|
|||
LIBIPMI_LIBS = @LIBIPMI_LIBS@
|
||||
LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@
|
||||
LIBLTDL_LIBS = @LIBLTDL_LIBS@
|
||||
LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@
|
||||
LIBMODBUS_LIBS = @LIBMODBUS_LIBS@
|
||||
LIBNEON_CFLAGS = @LIBNEON_CFLAGS@
|
||||
LIBNEON_LIBS = @LIBNEON_LIBS@
|
||||
LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@
|
||||
|
|
@ -200,21 +229,29 @@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@
|
|||
LIBS = @LIBS@
|
||||
LIBSSL_CFLAGS = @LIBSSL_CFLAGS@
|
||||
LIBSSL_LIBS = @LIBSSL_LIBS@
|
||||
LIBSSL_REQUIRES = @LIBSSL_REQUIRES@
|
||||
LIBTOOL = @LIBTOOL@
|
||||
LIBTOOL_DEPS = @LIBTOOL_DEPS@
|
||||
LIBUSB_CFLAGS = @LIBUSB_CFLAGS@
|
||||
LIBUSB_CONFIG = @LIBUSB_CONFIG@
|
||||
LIBUSB_LIBS = @LIBUSB_LIBS@
|
||||
LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@
|
||||
LIBWRAP_LIBS = @LIBWRAP_LIBS@
|
||||
LIPO = @LIPO@
|
||||
LN_S = @LN_S@
|
||||
LN_S_R = @LN_S_R@
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
|
||||
MAINT = @MAINT@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
MANIFEST_TOOL = @MANIFEST_TOOL@
|
||||
MKDIR_P = @MKDIR_P@
|
||||
NETLIBS = @NETLIBS@
|
||||
NET_SNMP_CONFIG = @NET_SNMP_CONFIG@
|
||||
NM = @NM@
|
||||
NMEDIT = @NMEDIT@
|
||||
NUT_DATADIR = @NUT_DATADIR@
|
||||
NUT_LIBEXECDIR = @NUT_LIBEXECDIR@
|
||||
NUT_NETVERSION = @NUT_NETVERSION@
|
||||
OBJDUMP = @OBJDUMP@
|
||||
OBJEXT = @OBJEXT@
|
||||
|
|
@ -234,6 +271,9 @@ PKG_CONFIG = @PKG_CONFIG@
|
|||
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
|
||||
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
|
||||
PORT = @PORT@
|
||||
PYTHON = @PYTHON@
|
||||
PYTHON2 = @PYTHON2@
|
||||
PYTHON3 = @PYTHON3@
|
||||
RANLIB = @RANLIB@
|
||||
RUN_AS_GROUP = @RUN_AS_GROUP@
|
||||
RUN_AS_USER = @RUN_AS_USER@
|
||||
|
|
@ -247,6 +287,7 @@ STATEPATH = @STATEPATH@
|
|||
STRIP = @STRIP@
|
||||
SUN_LIBUSB = @SUN_LIBUSB@
|
||||
TREE_VERSION = @TREE_VERSION@
|
||||
VALGRIND = @VALGRIND@
|
||||
VERSION = @VERSION@
|
||||
WORDS_BIGENDIAN = @WORDS_BIGENDIAN@
|
||||
XMLLINT = @XMLLINT@
|
||||
|
|
@ -264,6 +305,7 @@ am__leading_dot = @am__leading_dot@
|
|||
am__quote = @am__quote@
|
||||
am__tar = @am__tar@
|
||||
am__untar = @am__untar@
|
||||
auglensdir = @auglensdir@
|
||||
bindir = @bindir@
|
||||
build = @build@
|
||||
build_alias = @build_alias@
|
||||
|
|
@ -277,6 +319,9 @@ datarootdir = @datarootdir@
|
|||
devddir = @devddir@
|
||||
docdir = @docdir@
|
||||
driverexecdir = @driverexecdir@
|
||||
dummy_PKG_CONFIG = @dummy_PKG_CONFIG@
|
||||
dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@
|
||||
dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@
|
||||
dvidir = @dvidir@
|
||||
exec_prefix = @exec_prefix@
|
||||
host = @host@
|
||||
|
|
@ -302,12 +347,14 @@ pkgconfigdir = @pkgconfigdir@
|
|||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
sysconfdir = @sysconfdir@
|
||||
systemdsystemshutdowndir = @systemdsystemshutdowndir@
|
||||
systemdshutdowndir = @systemdshutdowndir@
|
||||
systemdsystemunitdir = @systemdsystemunitdir@
|
||||
systemdtmpfilesdir = @systemdtmpfilesdir@
|
||||
target = @target@
|
||||
target_alias = @target_alias@
|
||||
target_cpu = @target_cpu@
|
||||
|
|
@ -317,23 +364,34 @@ top_build_prefix = @top_build_prefix@
|
|||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
udevdir = @udevdir@
|
||||
EXTRA_DIST = README \
|
||||
app/gui-1.3.glade \
|
||||
app/NUT-Monitor \
|
||||
app/nut-monitor.appdata.xml \
|
||||
app/nut-monitor.desktop \
|
||||
app/nut-monitor.png \
|
||||
app/README \
|
||||
app/pixmaps/var-rw.png \
|
||||
app/pixmaps/on_line.png \
|
||||
app/pixmaps/warning.png \
|
||||
app/pixmaps/on_battery.png \
|
||||
app/pixmaps/var-ro.png \
|
||||
app/locale/fr/LC_MESSAGES/NUT-Monitor.mo \
|
||||
app/locale/it/LC_MESSAGES/NUT-Monitor.mo \
|
||||
module/PyNUT.py \
|
||||
module/test_nutclient.py
|
||||
EXTRA_DIST_PY2GTK2 = \
|
||||
app/ui/gui-1.3.glade \
|
||||
app/NUT-Monitor-py2gtk2.in \
|
||||
app/nut-monitor-py2gtk2.desktop
|
||||
|
||||
EXTRA_DIST_PY3QT5 = \
|
||||
app/ui/aboutdialog1.ui \
|
||||
app/ui/dialog1.ui \
|
||||
app/ui/dialog2.ui \
|
||||
app/ui/window1.ui \
|
||||
app/NUT-Monitor-py3qt5.in \
|
||||
app/nut-monitor-py3qt5.desktop
|
||||
|
||||
|
||||
# TODO: Make py2/py3-only builds, delivered preferred symlinks, etc. optional:
|
||||
EXTRA_DIST = README app/nut-monitor.appdata.xml \
|
||||
app/icons/48x48/nut-monitor.png \
|
||||
app/icons/64x64/nut-monitor.png \
|
||||
app/icons/256x256/nut-monitor.png \
|
||||
app/icons/scalable/nut-monitor.svg app/README \
|
||||
app/pixmaps/var-rw.png app/pixmaps/on_line.png \
|
||||
app/pixmaps/warning.png app/pixmaps/on_battery.png \
|
||||
app/pixmaps/var-ro.png \
|
||||
app/locale/fr/LC_MESSAGES/NUT-Monitor.mo \
|
||||
app/locale/it/LC_MESSAGES/NUT-Monitor.mo module/PyNUT.py.in \
|
||||
module/test_nutclient.py.in $(EXTRA_DIST_PY2GTK2) \
|
||||
$(EXTRA_DIST_PY3QT5)
|
||||
MAINTAINERCLEANFILES = Makefile.in .dirstamp
|
||||
all: all-am
|
||||
|
||||
.SUFFIXES:
|
||||
|
|
@ -349,14 +407,13 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi
|
|||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu scripts/python/Makefile'; \
|
||||
$(am__cd) $(top_srcdir) && \
|
||||
$(AUTOMAKE) --gnu scripts/python/Makefile
|
||||
.PRECIOUS: Makefile
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
@case '$?' in \
|
||||
*config.status*) \
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
|
||||
*) \
|
||||
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
|
||||
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
|
||||
esac;
|
||||
|
||||
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
|
||||
|
|
@ -380,7 +437,10 @@ ctags CTAGS:
|
|||
cscope cscopelist:
|
||||
|
||||
|
||||
distdir: $(DISTFILES)
|
||||
distdir: $(BUILT_SOURCES)
|
||||
$(MAKE) $(AM_MAKEFLAGS) distdir-am
|
||||
|
||||
distdir-am: $(DISTFILES)
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
list='$(DISTFILES)'; \
|
||||
|
|
@ -444,9 +504,10 @@ distclean-generic:
|
|||
maintainer-clean-generic:
|
||||
@echo "This command is intended for maintainers to use"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
-test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
|
||||
clean: clean-am
|
||||
|
||||
clean-am: clean-generic clean-libtool mostlyclean-am
|
||||
clean-am: clean-generic clean-libtool clean-local mostlyclean-am
|
||||
|
||||
distclean: distclean-am
|
||||
-rm -f Makefile
|
||||
|
|
@ -513,7 +574,7 @@ uninstall-am:
|
|||
.MAKE: install-am install-strip
|
||||
|
||||
.PHONY: all all-am check check-am clean clean-generic clean-libtool \
|
||||
cscopelist-am ctags-am distclean distclean-generic \
|
||||
clean-local cscopelist-am ctags-am distclean distclean-generic \
|
||||
distclean-libtool distdir dvi dvi-am html html-am info info-am \
|
||||
install install-am install-data install-data-am install-dvi \
|
||||
install-dvi-am install-exec install-exec-am install-html \
|
||||
|
|
@ -524,6 +585,11 @@ uninstall-am:
|
|||
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
|
||||
tags-am uninstall uninstall-am
|
||||
|
||||
.PRECIOUS: Makefile
|
||||
|
||||
|
||||
clean-local:
|
||||
rm -rf *.pyc __pycache__ */*.pyc */__pycache__ */*/*.pyc */*/__pycache__
|
||||
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ David Goncalves, and released under GPL v3.
|
|||
* "module": this directory contains PyNUT.py, which is a Python abstraction
|
||||
class to access NUT server(s). You can use it in Python programs to access NUT's
|
||||
upsd data server in a simple way, without having to know the NUT protocol.
|
||||
The same module should work for Python 2 and Python 3.
|
||||
|
||||
To import it on Python programs you have to use the following (case sensitive) :
|
||||
'import PyNUT'
|
||||
|
|
@ -17,16 +18,24 @@ data from an upsd data server.
|
|||
To install the PyNUT module on Debian/Ubuntu, copy it to:
|
||||
/usr/share/python-support/python-pynut/
|
||||
|
||||
For quick tests, just make sure its directory is exported in `PYTHONPATH`
|
||||
environment variable.
|
||||
|
||||
This directory also contains test_nutclient.py, which is a PyNUT test program.
|
||||
For this to be fully functional, you will need to adapt the login, password and
|
||||
upsname to fit your configuration.
|
||||
upsname to fit your configuration. A NUT data server should be running for the
|
||||
test program to verify connection and protocol support.
|
||||
|
||||
|
||||
* "app": this directory contains the NUT-Monitor application, that uses the
|
||||
PyNUT class, along with its resources.
|
||||
|
||||
To install it, you will either need to keep the files together, or to install:
|
||||
- NUT-Monitor to /usr/bin, /usr/X11R6/bin/ or something like that,
|
||||
- gui.glade to /usr/share/nut-monitor/,
|
||||
- Depending on the Python version(s) your system has, put NUT-Monitor-py2gtk2
|
||||
or NUT-Monitor-py3qt5 to /usr/bin/, /usr/X11R6/bin/ or something like that
|
||||
(optionally making a simple NUT-Monitor symlink to the preferred version),
|
||||
- ui/*.glade (for NUT-Monitor-py2gtk2) or ui/*.ui (for NUT-Monitor-py3qt5)
|
||||
to /usr/share/nut-monitor/,
|
||||
- nut-monitor.png to something like /usr/share/pixmaps/
|
||||
- and nut-monitor.desktop to /usr/share/applications
|
||||
- finally, nut-monitor-py2gtk2.desktop and/or nut-monitor-py3qt5.desktop
|
||||
(optionally symlinked as nut-monitor.desktop) to /usr/share/applications/
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
#!@PYTHON2@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# 2009-12-27 David Goncalves - Version 1.2
|
||||
|
|
@ -76,7 +76,7 @@ class interface :
|
|||
( cmd_opts, args ) = opt_parser.parse_args()
|
||||
|
||||
|
||||
self.__glade_file = os.path.join( os.path.dirname( sys.argv[0] ), "gui-1.3.glade" )
|
||||
self.__glade_file = os.path.join( os.path.dirname( sys.argv[0] ), "ui/gui-1.3.glade" )
|
||||
|
||||
self.__widgets["interface"] = gtk.glade.XML( self.__glade_file, "window1", APP )
|
||||
self.__widgets["main_window"] = self.__widgets["interface"].get_widget("window1")
|
||||
|
|
@ -486,7 +486,7 @@ class interface :
|
|||
self.gui_status_message( error_msg )
|
||||
|
||||
except :
|
||||
# Failed to get informations from the treeview... skip action
|
||||
# Failed to get information from the treeview... skip action
|
||||
pass
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
|
@ -813,7 +813,7 @@ class gui_updater( threading.Thread ) :
|
|||
self.__parent_class.gui_status_notification( _("Device is running on batteries"), "on_battery.png" )
|
||||
was_online = False
|
||||
|
||||
# Check for additionnal informations
|
||||
# Check for additionnal information
|
||||
for k,v in status_mapper.iteritems() :
|
||||
if vars.get("ups.status").find(k) != -1 :
|
||||
if ( text_right != "" ) :
|
||||
944
scripts/python/app/NUT-Monitor-py3qt5.in
Executable file
944
scripts/python/app/NUT-Monitor-py3qt5.in
Executable file
|
|
@ -0,0 +1,944 @@
|
|||
#!@PYTHON3@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# 2009-12-27 David Goncalves - Version 1.2
|
||||
# Total rewrite of NUT-Monitor to optimize GUI interaction.
|
||||
# Added favorites support (saved to user's home)
|
||||
# Added status icon on the notification area
|
||||
#
|
||||
# 2010-02-26 David Goncalves
|
||||
# Added UPS vars display and the possibility to change values
|
||||
# when user double-clicks on a RW var.
|
||||
#
|
||||
# 2010-05-01 David Goncalves
|
||||
# Added support for PyNotify (if available)
|
||||
#
|
||||
# 2010-05-05 David Goncalves
|
||||
# Added support for command line options
|
||||
# -> --start-hidden
|
||||
# -> --favorite
|
||||
#
|
||||
# NUT-Monitor now tries to detect if there is a NUT server
|
||||
# on localhost and if there is 1 UPS, connects to it.
|
||||
#
|
||||
# 2010-10-06 David Goncalves - Version 1.3
|
||||
# Added localisation support
|
||||
#
|
||||
# 2015-02-14 Michal Fincham - Version 1.3.1
|
||||
# Corrected unsafe permissions on ~/.nut-monitor (Debian #777706)
|
||||
#
|
||||
# 2022-02-20 Luke Dashjr - Version 2.0
|
||||
# Port to Python 3 with PyQt5.
|
||||
|
||||
|
||||
import PyQt5.uic
|
||||
from PyQt5.QtCore import *
|
||||
from PyQt5.QtGui import *
|
||||
from PyQt5.QtWidgets import *
|
||||
import sys
|
||||
import base64
|
||||
import os, os.path
|
||||
import stat
|
||||
import platform
|
||||
import time
|
||||
import threading
|
||||
import optparse
|
||||
import configparser
|
||||
import locale
|
||||
import gettext
|
||||
import PyNUT
|
||||
|
||||
|
||||
class interface :
|
||||
|
||||
DESIRED_FAVORITES_DIRECTORY_MODE = 0o700
|
||||
|
||||
__widgets = {}
|
||||
__callbacks = {}
|
||||
__favorites = {}
|
||||
__favorites_file = None
|
||||
__favorites_path = ""
|
||||
__fav_menu_items = list()
|
||||
__window_visible = True
|
||||
__ui_file = None
|
||||
__connected = False
|
||||
__ups_handler = None
|
||||
__ups_commands = None
|
||||
__ups_vars = None
|
||||
__ups_rw_vars = None
|
||||
__gui_thread = None
|
||||
__current_ups = None
|
||||
|
||||
def __init__( self, argv ) :
|
||||
|
||||
# Before anything, parse command line options if any present...
|
||||
opt_parser = optparse.OptionParser()
|
||||
opt_parser.add_option( "-H", "--start-hidden", action="store_true", default=False, dest="hidden", help="Start iconified in tray" )
|
||||
opt_parser.add_option( "-F", "--favorite", dest="favorite", help="Load the specified favorite and connect to UPS" )
|
||||
|
||||
( cmd_opts, args ) = opt_parser.parse_args()
|
||||
|
||||
|
||||
self.__app = QApplication( argv )
|
||||
|
||||
self.__ui_file = self.__find_res_file( 'ui', "window1.ui" )
|
||||
|
||||
self.__widgets["interface"] = PyQt5.uic.loadUi( self.__ui_file )
|
||||
self.__widgets["main_window"] = self.__widgets["interface"]
|
||||
self.__widgets["status_bar"] = self.__widgets["interface"].statusbar2
|
||||
self.__widgets["ups_host_entry"] = self.__widgets["interface"].entry1
|
||||
self.__widgets["ups_port_entry"] = self.__widgets["interface"].spinbutton1
|
||||
self.__widgets["ups_refresh_button"] = self.__widgets["interface"].button1
|
||||
self.__widgets["ups_authentication_check"] = self.__widgets["interface"].checkbutton1
|
||||
self.__widgets["ups_authentication_frame"] = self.__widgets["interface"].hbox1
|
||||
self.__widgets["ups_authentication_login"] = self.__widgets["interface"].entry2
|
||||
self.__widgets["ups_authentication_password"] = self.__widgets["interface"].entry3
|
||||
self.__widgets["ups_list_combo"] = self.__widgets["interface"].combobox1
|
||||
self.__widgets["ups_commands_combo"] = self.__widgets["interface"].ups_commands_combo
|
||||
self.__widgets["ups_commands_button"] = self.__widgets["interface"].button8
|
||||
self.__widgets["ups_connect"] = self.__widgets["interface"].button2
|
||||
self.__widgets["ups_disconnect"] = self.__widgets["interface"].button7
|
||||
self.__widgets["ups_params_box"] = self.__widgets["interface"].vbox6
|
||||
self.__widgets["ups_infos"] = self.__widgets["interface"].notebook1
|
||||
self.__widgets["ups_vars_tree"] = self.__widgets["interface"].treeview1
|
||||
self.__widgets["ups_vars_refresh"] = self.__widgets["interface"].button9
|
||||
self.__widgets["ups_status_image"] = self.__widgets["interface"].image1
|
||||
self.__widgets["ups_status_left"] = self.__widgets["interface"].label10
|
||||
self.__widgets["ups_status_right"] = self.__widgets["interface"].label11
|
||||
self.__widgets["ups_status_time"] = self.__widgets["interface"].label15
|
||||
self.__widgets["menu_favorites_root"] = self.__widgets["interface"].menu2
|
||||
self.__widgets["menu_favorites"] = self.__widgets["interface"].menu2
|
||||
self.__widgets["menu_favorites_add"] = self.__widgets["interface"].menuitem4
|
||||
self.__widgets["menu_favorites_del"] = self.__widgets["interface"].menuitem5
|
||||
self.__widgets["progress_battery_charge"] = self.__widgets["interface"].progressbar1
|
||||
self.__widgets["progress_battery_load"] = self.__widgets["interface"].progressbar2
|
||||
|
||||
# Create the tray icon and connect it to the show/hide method...
|
||||
self.__widgets["status_icon"] = QSystemTrayIcon( QIcon( self.__find_res_file( "pixmaps", "on_line.png" ) ) )
|
||||
self.__widgets["status_icon"].setVisible( True )
|
||||
self.__widgets["status_icon"].activated.connect( self.tray_activated )
|
||||
|
||||
self.__widgets["ups_status_image"].setPixmap( QPixmap( self.__find_res_file( "pixmaps", "on_line.png" ) ) )
|
||||
|
||||
# Connect interface callbacks actions
|
||||
self.__widgets["main_window"].destroyed.connect( self.quit )
|
||||
self.__widgets["interface"].imagemenuitem1.triggered.connect( self.gui_about_dialog )
|
||||
self.__widgets["interface"].imagemenuitem5.triggered.connect( self.quit )
|
||||
self.__widgets["ups_host_entry"].textChanged.connect( self.__check_gui_fields )
|
||||
self.__widgets["ups_authentication_login"].textChanged.connect( self.__check_gui_fields )
|
||||
self.__widgets["ups_authentication_password"].textChanged.connect( self.__check_gui_fields )
|
||||
self.__widgets["ups_authentication_check"].stateChanged.connect( self.__check_gui_fields )
|
||||
self.__widgets["ups_port_entry"].valueChanged.connect( self.__check_gui_fields )
|
||||
self.__widgets["ups_refresh_button"].clicked.connect( self.__update_ups_list )
|
||||
self.__widgets["ups_connect"].clicked.connect( self.connect_to_ups )
|
||||
self.__widgets["ups_disconnect"].clicked.connect( self.disconnect_from_ups )
|
||||
self.__widgets["ups_vars_refresh"].clicked.connect( self.__gui_update_ups_vars_view )
|
||||
self.__widgets["menu_favorites_add"].triggered.connect( self.__gui_add_favorite )
|
||||
self.__widgets["menu_favorites_del"].triggered.connect( self.__gui_delete_favorite )
|
||||
self.__widgets["ups_vars_tree"].doubleClicked.connect( self.__gui_ups_vars_selected )
|
||||
|
||||
# Remove the dummy combobox entry on UPS List and Commands
|
||||
self.__widgets["ups_list_combo"].removeItem( 0 )
|
||||
|
||||
# Set UPS vars treeview properties -----------------------------
|
||||
store = QStandardItemModel( 0, 3, self.__widgets["ups_vars_tree"] )
|
||||
self.__widgets["ups_vars_tree"].setModel( store )
|
||||
self.__widgets["ups_vars_tree"].setHeaderHidden( False )
|
||||
self.__widgets["ups_vars_tree"].setRootIsDecorated( False )
|
||||
|
||||
# Column 0
|
||||
store.setHeaderData( 0, Qt.Horizontal, '' )
|
||||
|
||||
# Column 1
|
||||
store.setHeaderData( 1, Qt.Horizontal, _('Var name') )
|
||||
|
||||
# Column 2
|
||||
store.setHeaderData( 2, Qt.Horizontal, _('Value') )
|
||||
self.__widgets["ups_vars_tree"].header().setStretchLastSection( True )
|
||||
|
||||
self.__widgets["ups_vars_tree"].sortByColumn( 1, Qt.AscendingOrder )
|
||||
self.__widgets["ups_vars_tree_store"] = store
|
||||
|
||||
self.__widgets["ups_vars_tree"].setMinimumSize( 0, 50 )
|
||||
#---------------------------------------------------------------
|
||||
|
||||
# UPS Commands combo box creation ------------------------------
|
||||
ups_commands_height = self.__widgets["ups_commands_combo"].size().height() * 2
|
||||
self.__widgets["ups_commands_combo"].setMinimumSize(0, ups_commands_height)
|
||||
self.__widgets["ups_commands_combo"].setCurrentIndex( 0 )
|
||||
|
||||
self.__widgets["ups_commands_button"].setMinimumSize(0, ups_commands_height)
|
||||
self.__widgets["ups_commands_button"].clicked.connect( self.__gui_send_ups_command )
|
||||
|
||||
self.__widgets["ups_commands_combo_store"] = self.__widgets["ups_commands_combo"]
|
||||
#---------------------------------------------------------------
|
||||
|
||||
self.gui_init_unconnected()
|
||||
|
||||
if ( cmd_opts.hidden != True ) :
|
||||
self.__widgets["main_window"].show()
|
||||
|
||||
# Define favorites path and load favorites
|
||||
if ( platform.system() == "Linux" ) :
|
||||
self.__favorites_path = os.path.join( os.environ.get("HOME"), ".nut-monitor" )
|
||||
elif ( platform.system() == "Windows" ) :
|
||||
self.__favorites_path = os.path.join( os.environ.get("USERPROFILE"), "Application Data", "NUT-Monitor" )
|
||||
|
||||
self.__favorites_file = os.path.join( self.__favorites_path, "favorites.ini" )
|
||||
self.__parse_favorites()
|
||||
|
||||
self.gui_status_message( _("Welcome to NUT Monitor") )
|
||||
|
||||
if ( cmd_opts.favorite != None ) :
|
||||
if ( cmd_opts.favorite in self.__favorites ) :
|
||||
self.__gui_load_favorite( fav_name=cmd_opts.favorite )
|
||||
self.connect_to_ups()
|
||||
else :
|
||||
# Try to scan localhost for available ups and connect to it if there is only one
|
||||
self.__widgets["ups_host_entry"].setText( "localhost" )
|
||||
self.__update_ups_list()
|
||||
if self.__widgets["ups_list_combo"].count() == 1:
|
||||
self.connect_to_ups()
|
||||
|
||||
def exec( self ) :
|
||||
self.__app.exec()
|
||||
|
||||
def __find_res_file( self, ftype, filename ) :
|
||||
filename = os.path.join( ftype, filename )
|
||||
# TODO: Skip checking application directory if installed
|
||||
path = os.path.join( os.path.dirname( sys.argv[0] ), filename )
|
||||
if os.path.exists(path):
|
||||
return path
|
||||
path = QStandardPaths.locate(QStandardPaths.AppDataLocation, filename)
|
||||
if os.path.exists(path):
|
||||
return path
|
||||
raise RuntimeError("Cannot find %s resource %s" % (ftype, filename))
|
||||
|
||||
def __find_icon_file( self ) :
|
||||
filename = 'nut-monitor.png'
|
||||
# TODO: Skip checking application directory if installed
|
||||
path = os.path.join( os.path.dirname( sys.argv[0] ), "icons", "256x256", filename )
|
||||
if os.path.exists(path):
|
||||
return path
|
||||
path = QStandardPaths.locate(QStandardPaths.AppDataLocation, os.path.join( "icons", "hicolor", "256x256", "apps", filename ) )
|
||||
if os.path.exists(path):
|
||||
return path
|
||||
raise RuntimeError("Cannot find %s resource %s" % ('icon', filename))
|
||||
|
||||
# Check if correct fields are filled to enable connection to the UPS
|
||||
def __check_gui_fields( self, widget=None ) :
|
||||
# If UPS list contains something, clear it
|
||||
if self.__widgets["ups_list_combo"].currentIndex() != -1 :
|
||||
self.__widgets["ups_list_combo"].clear()
|
||||
self.__widgets["ups_connect"].setEnabled( False )
|
||||
self.__widgets["menu_favorites_add"].setEnabled( False )
|
||||
|
||||
# Host/Port selection
|
||||
if len( self.__widgets["ups_host_entry"].text() ) > 0 :
|
||||
sensitive = True
|
||||
|
||||
# If authentication is selected, check that we have a login and password
|
||||
if self.__widgets["ups_authentication_check"].isChecked() :
|
||||
if len( self.__widgets["ups_authentication_login"].text() ) == 0 :
|
||||
sensitive = False
|
||||
|
||||
if len( self.__widgets["ups_authentication_password"].text() ) == 0 :
|
||||
sensitive = False
|
||||
|
||||
self.__widgets["ups_refresh_button"].setEnabled( sensitive )
|
||||
if not sensitive :
|
||||
self.__widgets["ups_connect"].setEnabled( False )
|
||||
self.__widgets["menu_favorites_add"].setEnabled( False )
|
||||
else :
|
||||
self.__widgets["ups_refresh_button"].setEnabled( False )
|
||||
self.__widgets["ups_connect"].setEnabled( False )
|
||||
self.__widgets["menu_favorites_add"].setEnabled( False )
|
||||
|
||||
# Use authentication fields...
|
||||
if self.__widgets["ups_authentication_check"].isChecked() :
|
||||
self.__widgets["ups_authentication_frame"].setEnabled( True )
|
||||
else :
|
||||
self.__widgets["ups_authentication_frame"].setEnabled( False )
|
||||
|
||||
self.gui_status_message()
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# This method is used to show/hide the main window when user clicks on the tray icon
|
||||
def tray_activated( self, widget=None, data=None ) :
|
||||
if self.__window_visible :
|
||||
self.__widgets["main_window"].hide()
|
||||
else :
|
||||
self.__widgets["main_window"].show()
|
||||
|
||||
self.__window_visible = not self.__window_visible
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# Change the status icon and tray icon
|
||||
def change_status_icon( self, icon="on_line", blink=False ) :
|
||||
self.__widgets["status_icon"].setIcon( QIcon( self.__find_res_file( "pixmaps", "%s.png" % icon ) ) )
|
||||
self.__widgets["ups_status_image"].setPixmap( QPixmap( self.__find_res_file( "pixmaps", "%s.png" % icon ) ) )
|
||||
# TODO self.__widgets["status_icon"].set_blinking( blink )
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# This method connects to the NUT server and retrieve availables UPSes
|
||||
# using connection parameters (host, port, login, pass...)
|
||||
def __update_ups_list( self, widget=None ) :
|
||||
|
||||
host = self.__widgets["ups_host_entry"].text()
|
||||
port = int( self.__widgets["ups_port_entry"].value() )
|
||||
login = None
|
||||
password = None
|
||||
|
||||
if self.__widgets["ups_authentication_check"].isChecked() :
|
||||
login = self.__widgets["ups_authentication_login"].text()
|
||||
password = self.__widgets["ups_authentication_password"].text()
|
||||
|
||||
try :
|
||||
nut_handler = PyNUT.PyNUTClient( host=host, port=port, login=login, password=password )
|
||||
upses = nut_handler.GetUPSList()
|
||||
|
||||
ups_list = list(key.decode('ascii') for key in upses.keys())
|
||||
ups_list.sort()
|
||||
|
||||
# If UPS list contains something, clear it
|
||||
self.__widgets["ups_list_combo"].clear()
|
||||
|
||||
for current in ups_list :
|
||||
self.__widgets["ups_list_combo"].addItem( current )
|
||||
|
||||
self.__widgets["ups_list_combo"].setCurrentIndex( 0 )
|
||||
|
||||
self.__widgets["ups_connect"].setEnabled( True )
|
||||
self.__widgets["menu_favorites_add"].setEnabled( True )
|
||||
|
||||
self.gui_status_message( _("Found {0} devices on {1}").format( len( ups_list ), host ) )
|
||||
|
||||
except :
|
||||
error_msg = _("Error connecting to '{0}' ({1})").format( host, sys.exc_info()[1] )
|
||||
self.gui_status_message( error_msg )
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# Quit program
|
||||
def quit( self, widget=None ) :
|
||||
# If we are connected to an UPS, disconnect first...
|
||||
if self.__connected :
|
||||
self.gui_status_message( _("Disconnecting from device") )
|
||||
self.disconnect_from_ups()
|
||||
|
||||
self.__app.quit()
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# Method called when user wants to add a new favorite entry. It
|
||||
# displays a dialog to enable user to select the name of the favorite
|
||||
def __gui_add_favorite( self, widget=None ) :
|
||||
dialog_ui_file = self.__find_res_file( 'ui', "dialog1.ui" )
|
||||
dialog = PyQt5.uic.loadUi( dialog_ui_file )
|
||||
|
||||
# Define interface callbacks actions
|
||||
def check_entry(val):
|
||||
if self.__gui_add_favorite_check_gui_fields(val):
|
||||
dialog.buttonBox.button(QDialogButtonBox.Ok).setEnabled( True )
|
||||
else:
|
||||
dialog.buttonBox.button(QDialogButtonBox.Ok).setEnabled( False )
|
||||
dialog.entry4.textChanged.connect( check_entry )
|
||||
|
||||
self.__widgets["main_window"].setEnabled( False )
|
||||
rc = dialog.exec()
|
||||
if rc == QDialog.Accepted :
|
||||
fav_data = {}
|
||||
fav_data["host"] = self.__widgets["ups_host_entry"].text()
|
||||
fav_data["port"] = "%d" % self.__widgets["ups_port_entry"].value()
|
||||
fav_data["ups"] = self.__widgets["ups_list_combo"].currentText()
|
||||
fav_data["auth"] = self.__widgets["ups_authentication_check"].isChecked()
|
||||
if fav_data["auth"] :
|
||||
fav_data["login"] = self.__widgets["ups_authentication_login"].text()
|
||||
fav_data["password"] = base64.b64encode( self.__widgets["ups_authentication_password"].text().encode('ascii') ).decode('ascii')
|
||||
|
||||
fav_name = dialog.entry4.text()
|
||||
self.__favorites[ fav_name ] = fav_data
|
||||
self.__gui_refresh_favorites_menu()
|
||||
|
||||
# Save all favorites
|
||||
self.__save_favorites()
|
||||
|
||||
self.__widgets["main_window"].setEnabled( True )
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# Method called when user wants to delete an entry from favorites
|
||||
def __gui_delete_favorite( self, widget=None ) :
|
||||
dialog_ui_file = self.__find_res_file( 'ui', "dialog2.ui" )
|
||||
dialog = PyQt5.uic.loadUi( dialog_ui_file )
|
||||
|
||||
# Remove the dummy combobox entry on list
|
||||
dialog.combobox2.removeItem( 0 )
|
||||
|
||||
favs = list(self.__favorites.keys())
|
||||
favs.sort()
|
||||
for current in favs :
|
||||
dialog.combobox2.addItem( current )
|
||||
|
||||
dialog.combobox2.setCurrentIndex( 0 )
|
||||
|
||||
self.__widgets["main_window"].setEnabled( False )
|
||||
rc = dialog.exec()
|
||||
fav_name = dialog.combobox2.currentText()
|
||||
self.__widgets["main_window"].setEnabled( True )
|
||||
|
||||
if ( rc == QDialog.Accepted ) :
|
||||
# Remove entry, show confirmation dialog
|
||||
resp = QMessageBox.question( None, self.__widgets["main_window"].windowTitle(), _("Are you sure that you want to remove this favorite ?"), QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes )
|
||||
|
||||
if ( resp == QMessageBox.Yes ) :
|
||||
del self.__favorites[ fav_name ]
|
||||
self.__gui_refresh_favorites_menu()
|
||||
self.__save_favorites()
|
||||
self.gui_status_message( _("Removed favorite '%s'") % fav_name )
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# Method called when user selects a favorite from the favorites menu
|
||||
def __gui_load_favorite( self, fav_name="" ) :
|
||||
|
||||
if ( fav_name in self.__favorites ) :
|
||||
# If auth is activated, process it before other fields to avoir weird
|
||||
# reactions with the 'check_gui_fields' function.
|
||||
if ( self.__favorites[fav_name].get("auth", False ) ) :
|
||||
self.__widgets["ups_authentication_check"].setChecked( True )
|
||||
self.__widgets["ups_authentication_login"].setText( self.__favorites[fav_name].get("login","") )
|
||||
self.__widgets["ups_authentication_password"].setText( self.__favorites[fav_name].get("password","") )
|
||||
|
||||
self.__widgets["ups_host_entry"].setText( self.__favorites[fav_name].get("host","") )
|
||||
self.__widgets["ups_port_entry"].setValue( int( self.__favorites[fav_name].get( "port", 3493 ) ) )
|
||||
|
||||
# Clear UPS list and add current UPS name
|
||||
self.__widgets["ups_list_combo"].clear()
|
||||
|
||||
self.__widgets["ups_list_combo"].addItem( self.__favorites[fav_name].get("ups","") )
|
||||
self.__widgets["ups_list_combo"].setCurrentIndex( 0 )
|
||||
|
||||
# Activate the connect button
|
||||
self.__widgets["ups_connect"].setEnabled( True )
|
||||
|
||||
self.gui_status_message( _("Loaded '%s'") % fav_name )
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# Send the selected command to the UPS
|
||||
def __gui_send_ups_command( self, widget=None ) :
|
||||
offset = self.__widgets["ups_commands_combo"].currentIndex()
|
||||
cmd = self.__ups_commands[ offset ].decode('ascii')
|
||||
|
||||
self.__widgets["main_window"].setEnabled( False )
|
||||
resp = QMessageBox.question( None, self.__widgets["main_window"].windowTitle(), _("Are you sure that you want to send '%s' to the device ?") % cmd, QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes )
|
||||
self.__widgets["main_window"].setEnabled( True )
|
||||
|
||||
if ( resp == QMessageBox.Yes ) :
|
||||
try :
|
||||
self.__ups_handler.RunUPSCommand( self.__current_ups, cmd )
|
||||
self.gui_status_message( _("Sent '{0}' command to {1}").format( cmd, self.__current_ups ) )
|
||||
|
||||
except :
|
||||
self.gui_status_message( _("Failed to send '{0}' ({1})").format( cmd, sys.exc_info()[1] ) )
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# Method called when user clicks on the UPS vars treeview. If the user
|
||||
# performs a double click on a RW var, the GUI shows the update var dialog.
|
||||
def __gui_ups_vars_selected( self, index ) :
|
||||
if True :
|
||||
model = self.__widgets["ups_vars_tree_store"]
|
||||
try :
|
||||
ups_var = model.data( index.siblingAtColumn(1) ).encode('ascii')
|
||||
if ( ups_var in self.__ups_rw_vars ) :
|
||||
# The selected var is RW, then we can show the update dialog
|
||||
|
||||
cur_val = self.__ups_rw_vars.get(ups_var).decode('ascii')
|
||||
|
||||
self.__widgets["main_window"].setEnabled( False )
|
||||
new_val, rc = QInputDialog.getText( None, self.__widgets["main_window"].windowTitle(), _("Enter a new value for the variable.<br><br>{0} = {1} <font color=\"#606060\"><i>(current value)</i></font>").format( ups_var, cur_val), QLineEdit.Normal, cur_val )
|
||||
self.__widgets["main_window"].setEnabled( True )
|
||||
|
||||
if ( rc ) :
|
||||
try :
|
||||
self.__ups_handler.SetRWVar( ups=self.__current_ups, var=ups_var.decode('ascii'), value=new_val )
|
||||
self.gui_status_message( _("Updated variable on %s") % self.__current_ups )
|
||||
|
||||
# Change the value on the local dict to update the GUI
|
||||
new_val = new_val.encode('ascii')
|
||||
self.__ups_vars[ups_var] = new_val
|
||||
self.__ups_rw_vars[ups_var] = new_val
|
||||
self.__gui_update_ups_vars_view()
|
||||
|
||||
except :
|
||||
error_msg = _("Error updating variable on '{0}' ({1})").format( self.__current_ups, sys.exc_info()[1] )
|
||||
self.gui_status_message( error_msg )
|
||||
|
||||
else :
|
||||
# User cancelled modification...
|
||||
error_msg = _("No variable modified on %s - User cancelled") % self.__current_ups
|
||||
self.gui_status_message( error_msg )
|
||||
|
||||
except :
|
||||
# Failed to get information from the treeview... skip action
|
||||
pass
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# Refresh the content of the favorites menu according to the defined favorites
|
||||
def __gui_refresh_favorites_menu( self ) :
|
||||
for current in self.__fav_menu_items :
|
||||
self.__widgets["menu_favorites"].removeAction(current)
|
||||
|
||||
self.__fav_menu_items = list()
|
||||
|
||||
items = list(self.__favorites.keys())
|
||||
items.sort()
|
||||
|
||||
for current in items :
|
||||
menu_item = QAction( current )
|
||||
self.__fav_menu_items.append( menu_item )
|
||||
self.__widgets["menu_favorites"].addAction( menu_item )
|
||||
|
||||
menu_item.triggered.connect( lambda: self.__gui_load_favorite( current ) )
|
||||
|
||||
if len( items ) > 0 :
|
||||
self.__widgets["menu_favorites_del"].setEnabled( True )
|
||||
else :
|
||||
self.__widgets["menu_favorites_del"].setEnabled( False )
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# In 'add favorites' dialog, this method compares the content of the
|
||||
# text widget representing the name of the new favorite with existing
|
||||
# ones. If they match, the 'add' button will be set to non sensitive
|
||||
# to avoid creating entries with the same name.
|
||||
def __gui_add_favorite_check_gui_fields( self, fav_name ) :
|
||||
if ( len( fav_name ) > 0 ) and ( fav_name not in list(self.__favorites.keys()) ) :
|
||||
return True
|
||||
else :
|
||||
return False
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# Load and parse favorites
|
||||
def __parse_favorites( self ) :
|
||||
|
||||
if ( not os.path.exists( self.__favorites_file ) ) :
|
||||
# There is no favorites files, do nothing
|
||||
return
|
||||
|
||||
try :
|
||||
if ( not stat.S_IMODE( os.stat( self.__favorites_path ).st_mode ) == self.DESIRED_FAVORITES_DIRECTORY_MODE ) : # unsafe pre-1.2 directory found
|
||||
os.chmod( self.__favorites_path, self.DESIRED_FAVORITES_DIRECTORY_MODE )
|
||||
|
||||
conf = configparser.ConfigParser()
|
||||
conf.read( self.__favorites_file )
|
||||
for current in conf.sections() :
|
||||
# Check if mandatory fields are present
|
||||
if ( conf.has_option( current, "host" ) and conf.has_option( current, "ups" ) ) :
|
||||
# Valid entry found, add it to the list
|
||||
fav_data = {}
|
||||
fav_data["host"] = conf.get( current, "host" )
|
||||
fav_data["ups"] = conf.get( current, "ups" )
|
||||
|
||||
if ( conf.has_option( current, "port" ) ) :
|
||||
fav_data["port"] = conf.get( current, "port" )
|
||||
else :
|
||||
fav_data["port"] = "3493"
|
||||
|
||||
# If auth is defined the section must have login and pass defined
|
||||
if ( conf.has_option( current, "auth" ) ) :
|
||||
if( conf.has_option( current, "login" ) and conf.has_option( current, "password" ) ) :
|
||||
# Add the entry
|
||||
fav_data["auth"] = conf.getboolean( current, "auth" )
|
||||
fav_data["login"] = conf.get( current, "login" )
|
||||
|
||||
try :
|
||||
fav_data["password"] = base64.decodebytes( conf.get( current, "password" ).encode('ascii') ).decode('ascii')
|
||||
|
||||
except :
|
||||
# If the password is not in base64, let the field empty
|
||||
print(( _("Error parsing favorites, password for '%s' is not in base64\nSkipping password for this entry") % current ))
|
||||
fav_data["password"] = ""
|
||||
else :
|
||||
fav_data["auth"] = False
|
||||
|
||||
self.__favorites[current] = fav_data
|
||||
self.__gui_refresh_favorites_menu()
|
||||
|
||||
except :
|
||||
self.gui_status_message( _("Error while parsing favorites file (%s)") % sys.exc_info()[1] )
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# Save favorites to the defined favorites file using ini format
|
||||
def __save_favorites( self ) :
|
||||
|
||||
# If path does not exists, try to create it
|
||||
if ( not os.path.exists( self.__favorites_file ) ) :
|
||||
try :
|
||||
os.makedirs( self.__favorites_path, mode=self.DESIRED_FAVORITES_DIRECTORY_MODE, exist_ok=True )
|
||||
except :
|
||||
self.gui_status_message( _("Error while creating configuration folder (%s)") % sys.exc_info()[1] )
|
||||
|
||||
save_conf = configparser.ConfigParser()
|
||||
for current in list(self.__favorites.keys()) :
|
||||
save_conf.add_section( current )
|
||||
for k, v in self.__favorites[ current ].items() :
|
||||
if isinstance( v, bool ) :
|
||||
v = str( v )
|
||||
save_conf.set( current, k, v )
|
||||
|
||||
try :
|
||||
fh = open( self.__favorites_file, "w" )
|
||||
save_conf.write( fh )
|
||||
fh.close()
|
||||
self.gui_status_message( _("Saved favorites...") )
|
||||
|
||||
except :
|
||||
self.gui_status_message( _("Error while saving favorites (%s)") % sys.exc_info()[1] )
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# Display the about dialog
|
||||
def gui_about_dialog( self, widget=None ) :
|
||||
self.__widgets["main_window"].adjustSize()
|
||||
dialog_ui_file = self.__find_res_file( 'ui', "aboutdialog1.ui" )
|
||||
|
||||
dialog = PyQt5.uic.loadUi( dialog_ui_file )
|
||||
dialog.icon.setPixmap( QPixmap( self.__find_icon_file() ) )
|
||||
|
||||
credits_button = QPushButton( dialog )
|
||||
credits_button.setText( _("C&redits") )
|
||||
credits_button.setIcon( dialog.style().standardIcon( QStyle.SP_MessageBoxInformation ) )
|
||||
credits_button.clicked.connect( self.gui_about_credits )
|
||||
|
||||
licence_button = QPushButton( dialog )
|
||||
licence_button.setText( _("&Licence") )
|
||||
licence_button.clicked.connect( self.gui_about_licence )
|
||||
|
||||
dialog.buttonBox.addButton( credits_button, QDialogButtonBox.HelpRole )
|
||||
dialog.buttonBox.addButton( licence_button, QDialogButtonBox.HelpRole )
|
||||
|
||||
self.__widgets["main_window"].setEnabled( False )
|
||||
dialog.exec()
|
||||
self.__widgets["main_window"].setEnabled( True )
|
||||
|
||||
def gui_about_credits( self ) :
|
||||
QMessageBox.about( None, _("Credits"), _("""
|
||||
Written by:
|
||||
David Goncalves <david@lestat.st>
|
||||
|
||||
Translated by:
|
||||
David Goncalves <david@lestat.st> - Français
|
||||
Daniele Pezzini <hyouko@gmail.com> - Italiano
|
||||
""").strip() )
|
||||
|
||||
def gui_about_licence( self ) :
|
||||
QMessageBox.about( None, _("Licence"), _("""
|
||||
Copyright (C) 2010 David Goncalves <david@lestat.st>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
""").strip() )
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# Display a message on the status bar. The message is also set as
|
||||
# tooltip to enable users to see long messages.
|
||||
def gui_status_message( self, msg="" ) :
|
||||
text = msg
|
||||
|
||||
message_id = self.__widgets["status_bar"].showMessage( text.replace("\n", "") )
|
||||
self.__widgets["status_bar"].setToolTip( text )
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# Display a notification using QSystemTrayIcon with an optional icon
|
||||
def gui_status_notification( self, message="", icon_file="" ) :
|
||||
if ( icon_file != "" ) :
|
||||
icon = QIcon( os.path.abspath( self.__find_res_file( "pixmaps", icon_file ) ) )
|
||||
else :
|
||||
icon = None
|
||||
|
||||
self.__widgets["status_icon"].showMessage( "NUT Monitor", message, icon )
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# Connect to the selected UPS using parameters (host,port,login,pass)
|
||||
def connect_to_ups( self, widget=None ) :
|
||||
|
||||
host = self.__widgets["ups_host_entry"].text()
|
||||
port = int( self.__widgets["ups_port_entry"].value() )
|
||||
login = None
|
||||
password = None
|
||||
|
||||
if self.__widgets["ups_authentication_check"].isChecked() :
|
||||
login = self.__widgets["ups_authentication_login"].text()
|
||||
password = self.__widgets["ups_authentication_password"].text()
|
||||
|
||||
try :
|
||||
self.__ups_handler = PyNUT.PyNUTClient( host=host, port=port, login=login, password=password )
|
||||
|
||||
except :
|
||||
self.gui_status_message( _("Error connecting to '{0}' ({1})").format( host, sys.exc_info()[1] ) )
|
||||
self.gui_status_notification( _("Error connecting to '{0}'\n{1}").format( host, sys.exc_info()[1] ), "warning.png" )
|
||||
return
|
||||
|
||||
# Check if selected UPS exists on server...
|
||||
srv_upses = self.__ups_handler.GetUPSList()
|
||||
self.__current_ups = self.__widgets["ups_list_combo"].currentText()
|
||||
|
||||
if self.__current_ups.encode('ascii') not in srv_upses :
|
||||
self.gui_status_message( _("Device '%s' not found on server") % self.__current_ups )
|
||||
self.gui_status_notification( _("Device '%s' not found on server") % self.__current_ups, "warning.png" )
|
||||
return
|
||||
|
||||
self.__connected = True
|
||||
self.__widgets["ups_connect"].hide()
|
||||
self.__widgets["ups_disconnect"].show()
|
||||
self.__widgets["ups_infos"].show()
|
||||
self.__widgets["ups_params_box"].setEnabled( False )
|
||||
self.__widgets["menu_favorites_root"].setEnabled( False )
|
||||
self.__widgets["ups_params_box"].hide()
|
||||
|
||||
commands = self.__ups_handler.GetUPSCommands( self.__current_ups )
|
||||
self.__ups_commands = list(commands.keys())
|
||||
self.__ups_commands.sort()
|
||||
|
||||
# Refresh UPS commands combo box
|
||||
self.__widgets["ups_commands_combo_store"].clear()
|
||||
for desc in self.__ups_commands :
|
||||
# TODO: Style as "%s<br><font color=\"#707070\">%s</font>"
|
||||
self.__widgets["ups_commands_combo_store"].addItem( "%s\n%s" % ( desc.decode('ascii'), commands[desc].decode('ascii') ) )
|
||||
|
||||
self.__widgets["ups_commands_combo"].setCurrentIndex( 0 )
|
||||
|
||||
# Update UPS vars manually before the thread
|
||||
self.__ups_vars = self.__ups_handler.GetUPSVars( self.__current_ups )
|
||||
self.__ups_rw_vars = self.__ups_handler.GetRWVars( self.__current_ups )
|
||||
self.__gui_update_ups_vars_view()
|
||||
|
||||
# Try to resize the main window...
|
||||
# FIXME: For some reason, calling this immediately doesn't work right
|
||||
QTimer.singleShot(10, self.__widgets["main_window"].adjustSize)
|
||||
|
||||
# Start the GUI updater thread
|
||||
self.__gui_thread = gui_updater( self )
|
||||
self.__gui_thread.start()
|
||||
|
||||
self.gui_status_message( _("Connected to '{0}' on {1}").format( self.__current_ups, host ) )
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# Refresh UPS vars in the treeview
|
||||
def __gui_update_ups_vars_view( self, widget=None ) :
|
||||
if self.__ups_handler :
|
||||
vars = self.__ups_vars
|
||||
rwvars = self.__ups_rw_vars
|
||||
|
||||
self.__widgets["ups_vars_tree_store"].removeRows(0, self.__widgets["ups_vars_tree_store"].rowCount())
|
||||
|
||||
for k,v in vars.items() :
|
||||
if ( k in rwvars ) :
|
||||
icon_file = self.__find_res_file( "pixmaps", "var-rw.png" )
|
||||
else :
|
||||
icon_file = self.__find_res_file( "pixmaps", "var-ro.png" )
|
||||
|
||||
icon = QIcon( icon_file )
|
||||
item_icon = QStandardItem(icon, '')
|
||||
item_icon.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemNeverHasChildren)
|
||||
item_var_name = QStandardItem( k.decode('ascii') )
|
||||
item_var_name.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemNeverHasChildren)
|
||||
item_var_val = QStandardItem( v.decode('ascii') )
|
||||
item_var_val.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemNeverHasChildren)
|
||||
self.__widgets["ups_vars_tree_store"].appendRow( (item_icon, item_var_name, item_var_val) )
|
||||
self.__widgets["ups_vars_tree"].resizeColumnToContents( 0 )
|
||||
self.__widgets["ups_vars_tree"].resizeColumnToContents( 1 )
|
||||
|
||||
|
||||
def gui_init_unconnected( self ) :
|
||||
self.__connected = False
|
||||
self.__widgets["ups_connect"].show()
|
||||
self.__widgets["ups_disconnect"].hide()
|
||||
self.__widgets["ups_infos"].hide()
|
||||
self.__widgets["ups_params_box"].setEnabled( True )
|
||||
self.__widgets["menu_favorites_root"].setEnabled( True )
|
||||
self.__widgets["status_icon"].setToolTip( _("<i>Not connected</i>") )
|
||||
self.__widgets["ups_params_box"].show()
|
||||
|
||||
# Try to resize the main window...
|
||||
self.__widgets["main_window"].adjustSize()
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# Disconnect from the UPS
|
||||
def disconnect_from_ups( self, widget=None ) :
|
||||
self.gui_init_unconnected()
|
||||
|
||||
# Stop the GUI updater thread
|
||||
self.__gui_thread.stop_thread()
|
||||
|
||||
del self.__ups_handler
|
||||
self.gui_status_message( _("Disconnected from '%s'") % self.__current_ups )
|
||||
self.change_status_icon( "on_line", blink=False )
|
||||
self.__current_ups = None
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# GUI Updater class
|
||||
# This class updates the main gui with data from connected UPS
|
||||
class gui_updater :
|
||||
|
||||
__parent_class = None
|
||||
__stop_thread = False
|
||||
|
||||
def __init__( self, parent_class ) :
|
||||
threading.Thread.__init__( self )
|
||||
self.__parent_class = parent_class
|
||||
|
||||
def start( self ) :
|
||||
self.__timer = QTimer()
|
||||
self.__timer.timeout.connect(self.__update)
|
||||
self.__timer.start(1000)
|
||||
|
||||
def __update( self ) :
|
||||
|
||||
ups = self.__parent_class._interface__current_ups
|
||||
was_online = True
|
||||
|
||||
# Define a dict containing different UPS status
|
||||
status_mapper = { b"LB" : "<font color=\"#BB0000\"><b>%s</b></font>" % _("Low batteries"),
|
||||
b"RB" : "<font color=\"#FF0000\"><b>%s</b></font>" % _("Replace batteries !"),
|
||||
b"BYPASS" : "<font color=\"#BB0000\">Bypass</font> <i>%s</i>" % _("(no battery protection)"),
|
||||
b"CAL" : _("Performing runtime calibration"),
|
||||
b"OFF" : "<font color=\"#000090\">%s</font> <i>(%s)</i>" % ( _("Offline"), _("not providing power to the load") ),
|
||||
b"OVER" : "<font color=\"#BB0000\">%s</font> <i>(%s)</i>" % ( _("Overloaded !"), _("there is too much load for device") ),
|
||||
b"TRIM" : _("Triming <i>(UPS is triming incoming voltage)</i>"),
|
||||
b"BOOST" : _("Boost <i>(UPS is boosting incoming voltage)</i>")
|
||||
}
|
||||
|
||||
if not self.__stop_thread :
|
||||
try :
|
||||
vars = self.__parent_class._interface__ups_handler.GetUPSVars( ups )
|
||||
self.__parent_class._interface__ups_vars = vars
|
||||
|
||||
# Text displayed on the status frame
|
||||
text_left = ""
|
||||
text_right = ""
|
||||
status_text = ""
|
||||
|
||||
text_left += "<b>%s</b><br>" % _("Device status :")
|
||||
|
||||
if ( vars.get(b"ups.status").find(b"OL") != -1 ) :
|
||||
text_right += "<font color=\"#009000\"><b>%s</b></font>" % _("Online")
|
||||
if not was_online :
|
||||
self.__parent_class.change_status_icon( "on_line", blink=False )
|
||||
was_online = True
|
||||
|
||||
if ( vars.get(b"ups.status").find(b"OB") != -1 ) :
|
||||
text_right += "<font color=\"#900000\"><b>%s</b></font>" % _("On batteries")
|
||||
if was_online :
|
||||
self.__parent_class.change_status_icon( "on_battery", blink=True )
|
||||
self.__parent_class.gui_status_notification( _("Device is running on batteries"), "on_battery.png" )
|
||||
was_online = False
|
||||
|
||||
# Check for additionnal information
|
||||
for k,v in status_mapper.items() :
|
||||
if vars.get(b"ups.status").find(k) != -1 :
|
||||
if ( text_right != "" ) :
|
||||
text_right += " - %s" % v
|
||||
else :
|
||||
text_right += "%s" % v
|
||||
|
||||
# CHRG and DISCHRG cannot be trated with the previous loop ;)
|
||||
if ( vars.get(b"ups.status").find(b"DISCHRG") != -1 ) :
|
||||
text_right += " - <i>%s</i>" % _("discharging")
|
||||
elif ( vars.get(b"ups.status").find(b"CHRG") != -1 ) :
|
||||
text_right += " - <i>%s</i>" % _("charging")
|
||||
|
||||
status_text += text_right
|
||||
text_right += "<br>"
|
||||
|
||||
if ( b"ups.mfr" in vars ) :
|
||||
text_left += "<b>%s</b><br><br>" % _("Model :")
|
||||
text_right += "%s<br>%s<br>" % (
|
||||
vars.get(b"ups.mfr",b"").decode('ascii'),
|
||||
vars.get(b"ups.model",b"").decode('ascii'),
|
||||
)
|
||||
|
||||
if ( b"ups.temperature" in vars ) :
|
||||
text_left += "<b>%s</b><br>" % _("Temperature :")
|
||||
text_right += "%s<br>" % int( float( vars.get( b"ups.temperature", 0 ) ) )
|
||||
|
||||
if ( b"battery.voltage" in vars ) :
|
||||
text_left += "<b>%s</b><br>" % _("Battery voltage :")
|
||||
text_right += "%sv<br>" % (vars.get( b"battery.voltage", 0 ).decode('ascii'),)
|
||||
|
||||
self.__parent_class._interface__widgets["ups_status_left"].setText( text_left[:-4] )
|
||||
self.__parent_class._interface__widgets["ups_status_right"].setText( text_right[:-4] )
|
||||
|
||||
# UPS load and battery charge progress bars
|
||||
self.__parent_class._interface__widgets["progress_battery_charge"].setRange( 0, 100 )
|
||||
if ( b"battery.charge" in vars ) :
|
||||
charge = vars.get( b"battery.charge", "0" )
|
||||
self.__parent_class._interface__widgets["progress_battery_charge"].setValue( int( float( charge ) ) )
|
||||
self.__parent_class._interface__widgets["progress_battery_charge"].resetFormat()
|
||||
status_text += "<br>%s %s%%" % ( _("Battery charge :"), int( float( charge ) ) )
|
||||
else :
|
||||
self.__parent_class._interface__widgets["progress_battery_charge"].setValue( 0 )
|
||||
self.__parent_class._interface__widgets["progress_battery_charge"].setFormat( _("Not available") )
|
||||
# FIXME: Some themes don't draw text, so swap it with a QLabel?
|
||||
|
||||
self.__parent_class._interface__widgets["progress_battery_load"].setRange( 0, 100 )
|
||||
if ( b"ups.load" in vars ) :
|
||||
load = vars.get( b"ups.load", "0" )
|
||||
self.__parent_class._interface__widgets["progress_battery_load"].setValue( int( float( load ) ) )
|
||||
self.__parent_class._interface__widgets["progress_battery_load"].resetFormat()
|
||||
status_text += "<br>%s %s%%" % ( _("UPS load :"), int( float( load ) ) )
|
||||
else :
|
||||
self.__parent_class._interface__widgets["progress_battery_load"].setValue( 0 )
|
||||
self.__parent_class._interface__widgets["progress_battery_load"].setFormat( _("Not available") )
|
||||
# FIXME: Some themes don't draw text, so swap it with a QLabel?
|
||||
|
||||
if ( b"battery.runtime" in vars ) :
|
||||
autonomy = int( float( vars.get( b"battery.runtime", 0 ) ) )
|
||||
|
||||
if ( autonomy >= 3600 ) :
|
||||
info = time.strftime( _("<b>%H hours %M minutes %S seconds</b>"), time.gmtime( autonomy ) )
|
||||
elif ( autonomy > 300 ) :
|
||||
info = time.strftime( _("<b>%M minutes %S seconds</b>"), time.gmtime( autonomy ) )
|
||||
else :
|
||||
info = time.strftime( _("<b><font color=\"#DD0000\">%M minutes %S seconds</font></b>"), time.gmtime( autonomy ) )
|
||||
else :
|
||||
info = _("Not available")
|
||||
|
||||
self.__parent_class._interface__widgets["ups_status_time"].setText( info )
|
||||
|
||||
# Display UPS status as tooltip for tray icon
|
||||
self.__parent_class._interface__widgets["status_icon"].setToolTip( status_text )
|
||||
|
||||
except :
|
||||
self.__parent_class.gui_status_message( _("Error from '{0}' ({1})").format( ups, sys.exc_info()[1] ) )
|
||||
self.__parent_class.gui_status_notification( _("Error from '{0}'\n{1}").format( ups, sys.exc_info()[1] ), "warning.png" )
|
||||
|
||||
def stop_thread( self ) :
|
||||
self.__timer.stop()
|
||||
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# The main program starts here :-)
|
||||
if __name__ == "__main__" :
|
||||
|
||||
# Init the localisation
|
||||
APP = "NUT-Monitor"
|
||||
DIR = "locale"
|
||||
|
||||
gettext.bindtextdomain( APP, DIR )
|
||||
gettext.textdomain( APP )
|
||||
_ = gettext.gettext
|
||||
|
||||
for module in ( gettext, ) :
|
||||
module.bindtextdomain( APP, DIR )
|
||||
module.textdomain( APP )
|
||||
|
||||
gui = interface(sys.argv)
|
||||
gui.exec()
|
||||
|
||||
|
|
@ -1,7 +1,55 @@
|
|||
NUT-Monitor is a graphical application to access and manager UPSes connected to
|
||||
NUT-Monitor
|
||||
===========
|
||||
|
||||
NUT-Monitor is a graphical application to access and manage UPSes connected to
|
||||
a NUT (Network UPS Tools) server.
|
||||
|
||||
This application (written in Python + GTK) uses the python-pynut class
|
||||
(available at http://www.lestat.st)
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
David Goncalves <david@lestat.st>
|
||||
This application (variants written in Python 2 + GTK2, and in Python 3 + Qt5)
|
||||
uses the python-pynut class (available at http://www.lestat.st), delivered
|
||||
as PyNUT in the NUT source tree.
|
||||
|
||||
Refer to your OS packaging and/or install custom modules with `pip` (or `pip3`)
|
||||
to get required dependencies (GTK + GObject or QT5).
|
||||
|
||||
Path to PyNUT module
|
||||
--------------------
|
||||
|
||||
For quick tests (e.g. during development), you can run the clients like this:
|
||||
````
|
||||
:; PYTHONPATH=../module/ python2 ./NUT-Monitor-py2gtk2.in
|
||||
````
|
||||
or:
|
||||
````
|
||||
:; PYTHONPATH=../module/ python3 ./NUT-Monitor-py3qt5.in
|
||||
````
|
||||
|
||||
Localization
|
||||
------------
|
||||
|
||||
For localized UI, also `export LANG=fr_FR.UTF-8` or `export LANG=ru_RU.UTF-8`
|
||||
(see and feel welcome to improve the choice of languages in `locale` directory).
|
||||
|
||||
NOTE: Currently localization only works for Python 2 client, PRs are welcome.
|
||||
|
||||
Desktop menu integration
|
||||
------------------------
|
||||
|
||||
This component ships both implementation-specific `nut-monitor-py2gtk2.desktop`
|
||||
and `nut-monitor-py3qt5.desktop` files which allows a user to have icons for
|
||||
both variants separately, as well as the legacy-named `nut-monitor.desktop`
|
||||
for running the wrapper script `NUT-Monitor` which picks an implementation best
|
||||
suited for current run-time circumstances.
|
||||
|
||||
Kudos
|
||||
-----
|
||||
|
||||
NUT-Monitor and PyNUT (for Python 2 syntax) were originally authored
|
||||
by David Goncalves <david@lestat.st>
|
||||
|
||||
NUT-Monitor was converted to Python 3 + QT5 by Luke Dashjr
|
||||
|
||||
PyNUT was extended, and two variants of NUT-Monitor converged and wrapped
|
||||
for Python 2+3 dual support by Jim Klimov
|
||||
|
|
|
|||
BIN
scripts/python/app/icons/256x256/nut-monitor.png
Normal file
BIN
scripts/python/app/icons/256x256/nut-monitor.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
BIN
scripts/python/app/icons/64x64/nut-monitor.png
Normal file
BIN
scripts/python/app/icons/64x64/nut-monitor.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.6 KiB |
490
scripts/python/app/icons/scalable/nut-monitor.svg
Normal file
490
scripts/python/app/icons/scalable/nut-monitor.svg
Normal file
|
|
@ -0,0 +1,490 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://web.resource.org/cc/"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="48"
|
||||
height="48"
|
||||
id="svg2"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.45"
|
||||
version="1.0"
|
||||
sodipodi:docbase="/home/dobey/Projects/gnome-icon-theme/scalable/devices"
|
||||
sodipodi:docname="battery.svg"
|
||||
inkscape:export-filename="/home/lapo/Desktop/per jimmac/scalable/devices/battery.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape">
|
||||
<defs
|
||||
id="defs4">
|
||||
<linearGradient
|
||||
id="linearGradient3367">
|
||||
<stop
|
||||
id="stop3369"
|
||||
offset="0"
|
||||
style="stop-color:#555753" />
|
||||
<stop
|
||||
style="stop-color:#8a8d85;stop-opacity:1;"
|
||||
offset="0.32156199"
|
||||
id="stop3371" />
|
||||
<stop
|
||||
style="stop-color:#babdb6;stop-opacity:1;"
|
||||
offset="0.53021115"
|
||||
id="stop3373" />
|
||||
<stop
|
||||
id="stop3375"
|
||||
offset="0.85266888"
|
||||
style="stop-color:#dcdeda;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop3377"
|
||||
offset="1"
|
||||
style="stop-color:#babdb6" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3351">
|
||||
<stop
|
||||
style="stop-color:#888a85"
|
||||
offset="0"
|
||||
id="stop3353" />
|
||||
<stop
|
||||
style="stop-color:#555753"
|
||||
offset="1"
|
||||
id="stop3355" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3290">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3292" />
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3294" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3280">
|
||||
<stop
|
||||
style="stop-color:#000000;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3282" />
|
||||
<stop
|
||||
style="stop-color:#000000;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3284" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3265">
|
||||
<stop
|
||||
style="stop-color:#c4a000;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3267" />
|
||||
<stop
|
||||
style="stop-color:#c4a000;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3269" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3254">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3256" />
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3258" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3236">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3238" />
|
||||
<stop
|
||||
style="stop-color:#fce94f"
|
||||
offset="1"
|
||||
id="stop3240" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3227">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3229" />
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3231" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3217">
|
||||
<stop
|
||||
style="stop-color:#c4a000;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3219" />
|
||||
<stop
|
||||
style="stop-color:#edd400"
|
||||
offset="1"
|
||||
id="stop3221" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3174">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3176" />
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3178" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3146">
|
||||
<stop
|
||||
id="stop3148"
|
||||
offset="0"
|
||||
style="stop-color:#c4a000" />
|
||||
<stop
|
||||
style="stop-color:#d8ba00;stop-opacity:1;"
|
||||
offset="0.35133624"
|
||||
id="stop3160" />
|
||||
<stop
|
||||
style="stop-color:#edd400;stop-opacity:1;"
|
||||
offset="0.50020754"
|
||||
id="stop3152" />
|
||||
<stop
|
||||
id="stop3162"
|
||||
offset="0.85000002"
|
||||
style="stop-color:#fdf4a7;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop3158"
|
||||
offset="1"
|
||||
style="stop-color:#fce94f" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3280"
|
||||
id="radialGradient3286"
|
||||
cx="21.34375"
|
||||
cy="14.125"
|
||||
fx="21.34375"
|
||||
fy="14.125"
|
||||
r="11.96875"
|
||||
gradientTransform="matrix(1,0,0,0.302872,8.341852e-16,9.846932)"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3236"
|
||||
id="radialGradient3337"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.690032,-4.583908e-18,1.406348e-18,0.228281,6.615871,10.90053)"
|
||||
cx="19.717636"
|
||||
cy="16.677069"
|
||||
fx="19.717636"
|
||||
fy="16.677069"
|
||||
r="12.46875" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3174"
|
||||
id="radialGradient3339"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.253821,-0.396912,0.124986,0.425706,-7.949749,14.71501)"
|
||||
cx="19.161945"
|
||||
cy="24.691038"
|
||||
fx="19.161945"
|
||||
fy="24.691038"
|
||||
r="12.46875" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3265"
|
||||
id="linearGradient3341"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="31.18708"
|
||||
y1="9.9904861"
|
||||
x2="25.531752"
|
||||
y2="18.613125" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3174"
|
||||
id="radialGradient3343"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.253821,-0.396912,0.124986,0.425706,-7.949749,14.71501)"
|
||||
cx="19.161945"
|
||||
cy="24.691038"
|
||||
fx="19.161945"
|
||||
fy="24.691038"
|
||||
r="12.46875" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3227"
|
||||
id="radialGradient3347"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.499279,-0.163895,3.603099e-2,0.557877,-10.01886,8.004429)"
|
||||
cx="19.863604"
|
||||
cy="11.205179"
|
||||
fx="19.863604"
|
||||
fy="11.205179"
|
||||
r="4" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3217"
|
||||
id="linearGradient3380"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(2,-4.760636e-13)"
|
||||
x1="18.5625"
|
||||
y1="11.1875"
|
||||
x2="17.71875"
|
||||
y2="12.534899" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3146"
|
||||
id="linearGradient3384"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(2,-4.760636e-13)"
|
||||
x1="25.500298"
|
||||
y1="10.985043"
|
||||
x2="17.499449"
|
||||
y2="10.985043" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3351"
|
||||
id="linearGradient3393"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="13.375"
|
||||
y1="23.221346"
|
||||
x2="13.375"
|
||||
y2="32.383766"
|
||||
gradientTransform="translate(-2,-4.760636e-13)" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3290"
|
||||
id="linearGradient3398"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="13.96536"
|
||||
y1="10.495919"
|
||||
x2="20.682875"
|
||||
y2="31.382992"
|
||||
gradientTransform="translate(2,0)" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3254"
|
||||
id="linearGradient3401"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(2,-4.760636e-13)"
|
||||
x1="12.25"
|
||||
y1="20.230709"
|
||||
x2="17.125"
|
||||
y2="34.173542" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3146"
|
||||
id="linearGradient3404"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(2,-4.760636e-13)"
|
||||
x1="33.5625"
|
||||
y1="19.125"
|
||||
x2="9.4987011"
|
||||
y2="19.125" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3367"
|
||||
id="linearGradient3407"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(2,-4.760636e-13)"
|
||||
x1="33.50008"
|
||||
y1="28.375"
|
||||
x2="9.4992361"
|
||||
y2="28.375" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1"
|
||||
inkscape:cx="34.743513"
|
||||
inkscape:cy="19.440609"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer5"
|
||||
showgrid="false"
|
||||
gridempspacing="2"
|
||||
gridspacingx="0.5px"
|
||||
gridspacingy="0.5px"
|
||||
inkscape:window-width="872"
|
||||
inkscape:window-height="771"
|
||||
inkscape:window-x="392"
|
||||
inkscape:window-y="55"
|
||||
stroke="#c4a000"
|
||||
inkscape:grid-points="false"
|
||||
inkscape:grid-bbox="true"
|
||||
fill="#555753"
|
||||
showborder="false"
|
||||
inkscape:showpageshadow="false" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>Lapo Calamandrei</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:title>Battery</dc:title>
|
||||
<dc:subject>
|
||||
<rdf:Bag>
|
||||
<rdf:li>battery</rdf:li>
|
||||
<rdf:li>recharge</rdf:li>
|
||||
<rdf:li>power</rdf:li>
|
||||
<rdf:li>acpi</rdf:li>
|
||||
<rdf:li>apm</rdf:li>
|
||||
</rdf:Bag>
|
||||
</dc:subject>
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
|
||||
</cc:Work>
|
||||
<cc:License
|
||||
rdf:about="http://creativecommons.org/licenses/GPL/2.0/">
|
||||
<cc:permits
|
||||
rdf:resource="http://web.resource.org/cc/Reproduction" />
|
||||
<cc:permits
|
||||
rdf:resource="http://web.resource.org/cc/Distribution" />
|
||||
<cc:requires
|
||||
rdf:resource="http://web.resource.org/cc/Notice" />
|
||||
<cc:permits
|
||||
rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
|
||||
<cc:requires
|
||||
rdf:resource="http://web.resource.org/cc/ShareAlike" />
|
||||
<cc:requires
|
||||
rdf:resource="http://web.resource.org/cc/SourceCode" />
|
||||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer6"
|
||||
inkscape:label="Shadow"
|
||||
style="display:inline">
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="opacity:0.7254902;color:#000000;fill:url(#radialGradient3286);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
|
||||
id="path3278"
|
||||
sodipodi:cx="21.34375"
|
||||
sodipodi:cy="14.125"
|
||||
sodipodi:rx="11.96875"
|
||||
sodipodi:ry="3.625"
|
||||
d="M 33.3125 14.125 A 11.96875 3.625 0 1 1 9.375,14.125 A 11.96875 3.625 0 1 1 33.3125 14.125 z"
|
||||
transform="matrix(1.389034,0,0,1.337644,-6.147196,18.98077)" />
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer2"
|
||||
inkscape:label="Battery"
|
||||
style="display:inline" />
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer4"
|
||||
inkscape:label="inner stroke"
|
||||
style="display:inline" />
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer5"
|
||||
inkscape:label="tip"
|
||||
style="display:inline">
|
||||
<path
|
||||
style="color:#000000;fill:url(#linearGradient3407);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
|
||||
d="M 22,10.5 C 16.084021,10.716519 11.5,12.21646 11.5,14 L 11.5,37 C 11.5,38.932002 16.876,40.500001 23.5,40.5 C 30.124,40.5 35.5,38.932003 35.5,37 L 35.5,14 C 35.5,12.067998 30.124001,10.5 23.5,10.5 C 23.13775,10.5 22.79161,10.490818 22.4375,10.5 C 22.294038,10.50372 22.141983,10.494804 22,10.5 z "
|
||||
id="path2230"
|
||||
sodipodi:nodetypes="csssssssc" />
|
||||
<path
|
||||
style="color:#000000;fill:url(#linearGradient3404);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
|
||||
d="M 22.4375,10.5 C 16.316456,10.658717 11.5,12.173655 11.5,14 L 11.5,20.5 C 11.5,22.432002 16.875999,24.000001 23.5,24 C 30.124,24 35.5,22.432001 35.5,20.5 L 35.5,14 C 35.5,12.067998 30.124,10.5 23.5,10.5 C 23.13775,10.5 22.79161,10.490818 22.4375,10.5 z "
|
||||
id="path2232"
|
||||
sodipodi:nodetypes="cssssssc" />
|
||||
<path
|
||||
style="opacity:0.36862745;color:#000000;fill:url(#linearGradient3401);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
|
||||
d="M 15,16 L 20,16 L 20,40.3125 L 15,39.5 L 15,16 z "
|
||||
id="rect3244"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
<path
|
||||
style="opacity:0.34509804;color:#000000;fill:url(#linearGradient3398);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
|
||||
d="M 22,10.5 C 16.084021,10.716519 11.5,12.21646 11.5,14 L 11.5,37 C 11.5,38.932002 16.876,40.500001 23.5,40.5 C 30.124,40.5 35.5,38.932003 35.5,37 L 35.5,14 C 35.5,12.067998 30.124001,10.5 23.5,10.5 C 23.13775,10.5 22.79161,10.490818 22.4375,10.5 C 22.294038,10.50372 22.141983,10.494804 22,10.5 z "
|
||||
id="path3288"
|
||||
sodipodi:nodetypes="csssssssc" />
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="color:#000000;fill:url(#radialGradient3337);fill-opacity:1;fill-rule:nonzero;stroke:url(#radialGradient3339);stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
|
||||
id="path3164"
|
||||
sodipodi:cx="21.34375"
|
||||
sodipodi:cy="14.125"
|
||||
sodipodi:rx="11.96875"
|
||||
sodipodi:ry="3.625"
|
||||
d="M 33.3125 14.125 A 11.96875 3.625 0 1 1 9.375,14.125 A 11.96875 3.625 0 1 1 33.3125 14.125 z"
|
||||
transform="matrix(1.002611,0,0,0.965518,2.100522,0.362061)" />
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="opacity:0.63921569;color:#000000;fill:url(#linearGradient3341);fill-opacity:1;fill-rule:nonzero;stroke:url(#radialGradient3343);stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
|
||||
id="path3263"
|
||||
sodipodi:cx="21.34375"
|
||||
sodipodi:cy="14.125"
|
||||
sodipodi:rx="11.96875"
|
||||
sodipodi:ry="3.625"
|
||||
d="M 33.3125 14.125 A 11.96875 3.625 0 1 1 9.375,14.125 A 11.96875 3.625 0 1 1 33.3125 14.125 z"
|
||||
transform="matrix(1.002611,0,0,0.965518,2.100522,0.362061)" />
|
||||
<path
|
||||
style="color:#000000;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient3393);stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
|
||||
d="M 11.5,21.5 L 11.5,37 C 11.5,38.932002 16.876,40.500001 23.5,40.5 C 30.124,40.5 35.5,38.932003 35.5,37 L 35.5,21.5"
|
||||
id="path2217"
|
||||
sodipodi:nodetypes="ccscc" />
|
||||
<path
|
||||
style="color:#000000;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#c4a000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
|
||||
d="M 35.5,21.5 L 35.5,14 C 35.5,12.067998 30.124001,10.5 23.5,10.5 C 23.13775,10.5 22.79161,10.490818 22.4375,10.5 C 22.294038,10.50372 22.141983,10.494804 22,10.5 C 16.084021,10.716519 11.5,12.21646 11.5,14 L 11.5,21.5"
|
||||
id="path2219"
|
||||
sodipodi:nodetypes="cssscsc" />
|
||||
<path
|
||||
style="opacity:0.49019608;color:#000000;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
|
||||
d="M 21.84375,11.5 C 16.548895,11.680925 12.5,12.74668 12.5,14 C 12.5,15.142813 12.5,35.855219 12.5,37 C 12.5,38.38 17.427994,39.5 23.5,39.5 C 29.572006,39.5 34.5,38.38 34.5,37 C 34.5,35.940784 34.499999,15.059216 34.5,14 C 34.5,12.62 29.572007,11.5 23.5,11.5 C 23.1205,11.5 22.744639,11.49146 22.375,11.5 C 22.201732,11.504003 22.014552,11.494164 21.84375,11.5 z "
|
||||
id="path2206"
|
||||
sodipodi:nodetypes="csssssssc" />
|
||||
<path
|
||||
style="color:#000000;fill:url(#linearGradient3384);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
|
||||
d="M 23,9.5 C 21.315666,9.5803665 19.950192,10.074035 19.59375,10.6875 C 19.587086,10.699702 19.568368,10.737692 19.5625,10.75 C 19.559767,10.75618 19.533781,10.775045 19.53125,10.78125 C 19.528923,10.78748 19.533372,10.806246 19.53125,10.8125 C 19.521672,10.843887 19.504323,10.905557 19.5,10.9375 C 19.49935,10.943909 19.500435,10.96232 19.5,10.96875 C 19.499782,10.975199 19.5,12.993531 19.5,13 C 19.5,13.006469 19.499782,13.024801 19.5,13.03125 C 19.500435,13.03768 19.49935,13.056091 19.5,13.0625 C 19.504323,13.094443 19.521672,13.156113 19.53125,13.1875 C 19.533372,13.193754 19.528923,13.21252 19.53125,13.21875 C 19.533781,13.224955 19.559767,13.24382 19.5625,13.25 C 19.568368,13.262308 19.587086,13.300298 19.59375,13.3125 C 19.985483,13.986704 21.58525,14.5 23.5,14.5 C 25.41475,14.5 27.014517,13.986704 27.40625,13.3125 C 27.412914,13.300298 27.431632,13.262308 27.4375,13.25 C 27.440233,13.24382 27.466219,13.224955 27.46875,13.21875 C 27.471077,13.21252 27.466628,13.193754 27.46875,13.1875 C 27.478328,13.156113 27.495677,13.094443 27.5,13.0625 C 27.50065,13.056091 27.499565,13.03768 27.5,13.03125 C 27.500218,13.024801 27.5,13.006469 27.5,13 C 27.5,12.993531 27.500218,10.975199 27.5,10.96875 C 27.499565,10.96232 27.50065,10.943909 27.5,10.9375 C 27.495677,10.905557 27.478328,10.843887 27.46875,10.8125 C 27.466628,10.806246 27.471077,10.78748 27.46875,10.78125 C 27.466219,10.775045 27.440233,10.75618 27.4375,10.75 C 27.431632,10.737692 27.412914,10.699702 27.40625,10.6875 C 27.014517,10.013296 25.41475,9.5 23.5,9.5 C 23.3275,9.5 23.166766,9.4920429 23,9.5 z "
|
||||
id="path3198"
|
||||
sodipodi:nodetypes="cssssssssssssssssssssssssssssc" />
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="color:#000000;fill:url(#radialGradient3347);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
|
||||
id="path3225"
|
||||
sodipodi:cx="21.5"
|
||||
sodipodi:cy="11"
|
||||
sodipodi:rx="4"
|
||||
sodipodi:ry="1.5"
|
||||
d="M 25.5 11 A 4 1.5 0 1 1 17.5,11 A 4 1.5 0 1 1 25.5 11 z"
|
||||
transform="matrix(0.867417,0,0,0.666667,4.820203,3.666665)" />
|
||||
<path
|
||||
style="color:#000000;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient3380);stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
|
||||
d="M 23,9.5 C 21.315666,9.5803665 19.950192,10.074035 19.59375,10.6875 C 19.587086,10.699702 19.568368,10.737692 19.5625,10.75 C 19.559767,10.75618 19.533781,10.775045 19.53125,10.78125 C 19.528923,10.78748 19.533372,10.806246 19.53125,10.8125 C 19.521672,10.843887 19.504323,10.905557 19.5,10.9375 C 19.49935,10.943909 19.500435,10.96232 19.5,10.96875 C 19.499782,10.975199 19.5,12.993531 19.5,13 C 19.5,13.006469 19.499782,13.024801 19.5,13.03125 C 19.500435,13.03768 19.49935,13.056091 19.5,13.0625 C 19.504323,13.094443 19.521672,13.156113 19.53125,13.1875 C 19.533372,13.193754 19.528923,13.21252 19.53125,13.21875 C 19.533781,13.224955 19.559767,13.24382 19.5625,13.25 C 19.568368,13.262308 19.587086,13.300298 19.59375,13.3125 C 19.985483,13.986704 21.58525,14.5 23.5,14.5 C 25.41475,14.5 27.014517,13.986704 27.40625,13.3125 C 27.412914,13.300298 27.431632,13.262308 27.4375,13.25 C 27.440233,13.24382 27.466219,13.224955 27.46875,13.21875 C 27.471077,13.21252 27.466628,13.193754 27.46875,13.1875 C 27.478328,13.156113 27.495677,13.094443 27.5,13.0625 C 27.50065,13.056091 27.499565,13.03768 27.5,13.03125 C 27.500218,13.024801 27.5,13.006469 27.5,13 C 27.5,12.993531 27.500218,10.975199 27.5,10.96875 C 27.499565,10.96232 27.50065,10.943909 27.5,10.9375 C 27.495677,10.905557 27.478328,10.843887 27.46875,10.8125 C 27.466628,10.806246 27.471077,10.78748 27.46875,10.78125 C 27.466219,10.775045 27.440233,10.75618 27.4375,10.75 C 27.431632,10.737692 27.412914,10.699702 27.40625,10.6875 C 27.014517,10.013296 25.41475,9.5 23.5,9.5 C 23.3275,9.5 23.166766,9.4920429 23,9.5 z "
|
||||
id="path3205"
|
||||
sodipodi:nodetypes="cssssssssssssssssssssssssssssc" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 23 KiB |
11
scripts/python/app/nut-monitor-py2gtk2.desktop
Normal file
11
scripts/python/app/nut-monitor-py2gtk2.desktop
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
[Desktop Entry]
|
||||
Name=NUT Monitor
|
||||
Name[fr]=Moniteur NUT
|
||||
Comment=Network UPS Tools GUI client (Py2Gtk2)
|
||||
Comment[fr]=Client graphique pour NUT (Network UPS Tools, Py2Gtk2)
|
||||
Comment[it]=Client grafico per NUT (Network UPS Tools, Py2Gtk2)
|
||||
Categories=System;Monitor;HardwareSettings;Settings;GTK
|
||||
Exec=NUT-Monitor-py2gtk2
|
||||
Icon=nut-monitor
|
||||
Terminal=false
|
||||
Type=Application
|
||||
11
scripts/python/app/nut-monitor-py3qt5.desktop
Normal file
11
scripts/python/app/nut-monitor-py3qt5.desktop
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
[Desktop Entry]
|
||||
Name=NUT Monitor
|
||||
Name[fr]=Moniteur NUT
|
||||
Comment=Network UPS Tools GUI client (Py3Qt5)
|
||||
Comment[fr]=Client graphique pour NUT (Network UPS Tools, Py3Qt5)
|
||||
Comment[it]=Client grafico per NUT (Network UPS Tools, Py3Qt5)
|
||||
Categories=System;Monitor;HardwareSettings;Settings;Qt
|
||||
Exec=NUT-Monitor-py3qt5
|
||||
Icon=nut-monitor
|
||||
Terminal=false
|
||||
Type=Application
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Copyright 2014 Arnaud Quette <arnaud.quette@free.fr> -->
|
||||
<application>
|
||||
<id type="desktop">nut-monitor.desktop</id>
|
||||
<component type="desktop-application">
|
||||
<id>nut-monitor.desktop</id>
|
||||
<metadata_license>CC0-1.0</metadata_license>
|
||||
<project_license>GPL-3.0+</project_license>
|
||||
<name>NUT Monitor</name>
|
||||
|
|
@ -32,11 +32,17 @@
|
|||
</p>
|
||||
</description>
|
||||
<screenshots>
|
||||
<screenshot type="default" width="620" height="349">http://www.lestat.st/_media/informatique/projets/nut-monitor/nut-monitor-1.png</screenshot>
|
||||
<screenshot width="620" height="349">http://www.lestat.st/_media/informatique/projets/nut-monitor/nut-monitor-2.png</screenshot>
|
||||
<screenshot width="620" height="349">http://www.lestat.st/_media/informatique/projets/nut-monitor/nut-monitor-3.png</screenshot>
|
||||
<screenshot type="default" width="620" height="349">
|
||||
<image>https://www.lestat.st/_media/informatique/projets/nut-monitor/nut-monitor-1.png</image>
|
||||
</screenshot>
|
||||
<screenshot width="620" height="349">
|
||||
<image>https://www.lestat.st/_media/informatique/projets/nut-monitor/nut-monitor-2.png</image>
|
||||
</screenshot>
|
||||
<screenshot width="620" height="349">
|
||||
<image>https://www.lestat.st/_media/informatique/projets/nut-monitor/nut-monitor-3.png</image>
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
<url type="homepage">http://www.lestat.st/en/informatique/projets/nut-monitor</url>
|
||||
<updatecontact>david@lestat.st</updatecontact>
|
||||
<url type="homepage">https://www.lestat.st/en/informatique/projets/nut-monitor</url>
|
||||
<update_contact>david@lestat.st</update_contact>
|
||||
<!-- project_group>GNOME</project_group -->
|
||||
</application>
|
||||
</component>
|
||||
|
|
|
|||
|
|
@ -1,12 +0,0 @@
|
|||
[Desktop Entry]
|
||||
Name=NUT Monitor
|
||||
Name[fr]=Moniteur NUT
|
||||
Comment=Network UPS Tools GUI client
|
||||
Comment[fr]=Client graphique pour NUT (Network UPS Tools)
|
||||
Comment[it]=Client grafico per NUT (Network UPS Tools)
|
||||
Categories=Application;Network;
|
||||
Encoding=UTF-8
|
||||
Exec=NUT-Monitor
|
||||
Icon=nut-monitor.png
|
||||
Terminal=false
|
||||
Type=Application
|
||||
108
scripts/python/app/ui/aboutdialog1.ui
Normal file
108
scripts/python/app/ui/aboutdialog1.ui
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>aboutdialog1</class>
|
||||
<widget class="QDialog" name="aboutdialog1">
|
||||
<property name="windowTitle">
|
||||
<string>About NUT-Monitor</string>
|
||||
</property>
|
||||
<property name="modal">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="icon">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string><h1>NUT-Monitor 1.3.1</h1>
|
||||
<p>GUI to manage devices connected a NUT server.</p>
|
||||
<p>For more information about NUT (Network UPS Tools) please visit the author's website.</p>
|
||||
<p style="margin-bottom: 1.5em">http://www.networkupstools.org</p>
|
||||
<p style=" font-size:8pt;">Copyright (c) 2010 David Goncalves</p>
|
||||
<p><a href="http://www.lestat.st/informatique/projets/nut-monitor-en">http://www.lestat.st</a></p></string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::RichText</enum>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>aboutdialog1</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>aboutdialog1</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
89
scripts/python/app/ui/dialog1.ui
Normal file
89
scripts/python/app/ui/dialog1.ui
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>dialog1</class>
|
||||
<widget class="QDialog" name="dialog1">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>297</width>
|
||||
<height>133</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
</property>
|
||||
<property name="modal">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QFrame" name="frame2">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label5">
|
||||
<property name="text">
|
||||
<string>Enter a name for this favorite<br><br><font color="#808080">You cannot re-use a name from another entry</font></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="entry4"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>dialog1</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>dialog1</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
98
scripts/python/app/ui/dialog2.ui
Normal file
98
scripts/python/app/ui/dialog2.ui
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>dialog2</class>
|
||||
<widget class="QDialog" name="dialog2">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>229</width>
|
||||
<height>116</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
</property>
|
||||
<property name="modal">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QFrame" name="frame3">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="vbox4">
|
||||
<item>
|
||||
<widget class="QLabel" name="label5">
|
||||
<property name="text">
|
||||
<string>Please select the favorite that you want to delete from list...</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="combobox2">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>None</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>dialog2</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>dialog2</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
473
scripts/python/app/ui/window1.ui
Normal file
473
scripts/python/app/ui/window1.ui
Normal file
|
|
@ -0,0 +1,473 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>window1</class>
|
||||
<widget class="QMainWindow" name="window1">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>560</width>
|
||||
<height>465</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>NUT Monitor</string>
|
||||
</property>
|
||||
<property name="windowIcon">
|
||||
<iconset theme="battery">
|
||||
<normaloff>../../../../../.designer/backup</normaloff>../../../../../.designer/backup</iconset>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox1">
|
||||
<property name="title">
|
||||
<string> NUT Server </string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QWidget" name="vbox6" native="true">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="table1">
|
||||
<item row="0" column="2">
|
||||
<widget class="QSpinBox" name="spinbutton1">
|
||||
<property name="maximum">
|
||||
<number>65535</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>3493</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="entry1"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label3">
|
||||
<property name="text">
|
||||
<string>Device : </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="combobox1">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>None</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label2">
|
||||
<property name="text">
|
||||
<string>Host / Port : </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="button1">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Refresh</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="view-refresh"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkbutton1">
|
||||
<property name="text">
|
||||
<string>Use authentication</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="hbox1" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label4">
|
||||
<property name="text">
|
||||
<string>Login / Password : </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="entry2"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="entry3">
|
||||
<property name="echoMode">
|
||||
<enum>QLineEdit::Password</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="hseparator1">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::HLine</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Sunken</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="hbox2">
|
||||
<item>
|
||||
<widget class="QPushButton" name="button2">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>C&onnect</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="network-connect"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="button7">
|
||||
<property name="text">
|
||||
<string>&Disconnect</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="network-disconnect"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTabWidget" name="notebook1">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="vbox7">
|
||||
<attribute name="title">
|
||||
<string>Device status</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="hbox3">
|
||||
<item>
|
||||
<widget class="QLabel" name="image1">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="frame4">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label10">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>label</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label11">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>label</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="table2">
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label14">
|
||||
<property name="text">
|
||||
<string>Remaining time :</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label12">
|
||||
<property name="text">
|
||||
<string>Battery charge :</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QProgressBar" name="progressbar2">
|
||||
<property name="value">
|
||||
<number>24</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label16">
|
||||
<property name="text">
|
||||
<string>Device commands :</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QProgressBar" name="progressbar1">
|
||||
<property name="value">
|
||||
<number>24</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label13">
|
||||
<property name="text">
|
||||
<string>Current load :</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QFrame" name="frame5">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label15">
|
||||
<property name="text">
|
||||
<string>N/A</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<layout class="QHBoxLayout" name="hbox5">
|
||||
<item>
|
||||
<widget class="QComboBox" name="ups_commands_combo">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QComboBox::AdjustToContents</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="button8">
|
||||
<property name="text">
|
||||
<string>&Execute</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="system-run"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="vbox8">
|
||||
<attribute name="title">
|
||||
<string>Device vars</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QFrame" name="frame6">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<widget class="QTreeView" name="treeview1"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="button9">
|
||||
<property name="text">
|
||||
<string>&Refresh</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="view-refresh"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menubar1">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>560</width>
|
||||
<height>24</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menu1">
|
||||
<property name="title">
|
||||
<string>&File</string>
|
||||
</property>
|
||||
<addaction name="imagemenuitem1"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="imagemenuitem5"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menu2">
|
||||
<property name="title">
|
||||
<string>F&avorites</string>
|
||||
</property>
|
||||
<addaction name="menuitem4"/>
|
||||
<addaction name="menuitem5"/>
|
||||
<addaction name="separator"/>
|
||||
</widget>
|
||||
<addaction name="menu1"/>
|
||||
<addaction name="menu2"/>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar2"/>
|
||||
<action name="imagemenuitem1">
|
||||
<property name="icon">
|
||||
<iconset theme="help-about"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&About</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="imagemenuitem5">
|
||||
<property name="icon">
|
||||
<iconset theme="application-exit"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Quit</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Q</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="menuitem4">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="bookmark-new"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Add</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="menuitem5">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="bookmark-remove"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Delete</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
#!@PYTHON@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2008 David Goncalves <david@lestat.st>
|
||||
|
|
@ -38,6 +38,11 @@
|
|||
# 2014-06-03 george2 - Version 1.3.0
|
||||
# Added custom exception class, fixed minor bug, added Python 3 support.
|
||||
#
|
||||
# 2021-09-27 Jim Klimov <jimklimov+nut@gmail.com> - Version 1.4.0
|
||||
# Revise strings used to be byte sequences as required by telnetlib
|
||||
# in Python 3.9, by spelling out b"STR" or str.encode('ascii');
|
||||
# the change was also tested to work with Python 2.7, 3.4, 3.5 and
|
||||
# 3.7 (to the extent of accompanying test_nutclient.py at least).
|
||||
|
||||
import telnetlib
|
||||
|
||||
|
|
@ -56,8 +61,8 @@ class PyNUTClient :
|
|||
__timeout = None
|
||||
__srv_handler = None
|
||||
|
||||
__version = "1.3.0"
|
||||
__release = "2014-06-03"
|
||||
__version = "1.4.0"
|
||||
__release = "2021-09-27"
|
||||
|
||||
|
||||
def __init__( self, host="127.0.0.1", port=3493, login=None, password=None, debug=False, timeout=5 ) :
|
||||
|
|
@ -89,7 +94,7 @@ timeout : Timeout used to wait for network response
|
|||
def __del__( self ) :
|
||||
""" Class destructor method """
|
||||
try :
|
||||
self.__srv_handler.write( "LOGOUT\n" )
|
||||
self.__srv_handler.write( b"LOGOUT\n" )
|
||||
except :
|
||||
pass
|
||||
|
||||
|
|
@ -105,16 +110,16 @@ if something goes wrong.
|
|||
self.__srv_handler = telnetlib.Telnet( self.__host, self.__port )
|
||||
|
||||
if self.__login != None :
|
||||
self.__srv_handler.write( "USERNAME %s\n" % self.__login )
|
||||
result = self.__srv_handler.read_until( "\n", self.__timeout )
|
||||
if result[:2] != "OK" :
|
||||
raise PyNUTError( result.replace( "\n", "" ) )
|
||||
self.__srv_handler.write( ("USERNAME %s\n" % self.__login).encode('ascii') )
|
||||
result = self.__srv_handler.read_until( b"\n", self.__timeout )
|
||||
if result[:2] != b"OK" :
|
||||
raise PyNUTError( result.replace( b"\n", b"" ) )
|
||||
|
||||
if self.__password != None :
|
||||
self.__srv_handler.write( "PASSWORD %s\n" % self.__password )
|
||||
result = self.__srv_handler.read_until( "\n", self.__timeout )
|
||||
if result[:2] != "OK" :
|
||||
raise PyNUTError( result.replace( "\n", "" ) )
|
||||
self.__srv_handler.write( ("PASSWORD %s\n" % self.__password).encode('ascii') )
|
||||
result = self.__srv_handler.read_until( b"\n", self.__timeout )
|
||||
if result[:2] != b"OK" :
|
||||
raise PyNUTError( result.replace( b"\n", b"" ) )
|
||||
|
||||
def GetUPSList( self ) :
|
||||
""" Returns the list of available UPS from the NUT server
|
||||
|
|
@ -124,18 +129,18 @@ The result is a dictionary containing 'key->val' pairs of 'UPSName' and 'UPS Des
|
|||
if self.__debug :
|
||||
print( "[DEBUG] GetUPSList from server" )
|
||||
|
||||
self.__srv_handler.write( "LIST UPS\n" )
|
||||
result = self.__srv_handler.read_until( "\n" )
|
||||
if result != "BEGIN LIST UPS\n" :
|
||||
raise PyNUTError( result.replace( "\n", "" ) )
|
||||
self.__srv_handler.write( b"LIST UPS\n" )
|
||||
result = self.__srv_handler.read_until( b"\n" )
|
||||
if result != b"BEGIN LIST UPS\n" :
|
||||
raise PyNUTError( result.replace( b"\n", b"" ) )
|
||||
|
||||
result = self.__srv_handler.read_until( "END LIST UPS\n" )
|
||||
result = self.__srv_handler.read_until( b"END LIST UPS\n" )
|
||||
ups_list = {}
|
||||
|
||||
for line in result.split( "\n" ) :
|
||||
if line[:3] == "UPS" :
|
||||
ups, desc = line[4:-1].split( '"' )
|
||||
ups_list[ ups.replace( " ", "" ) ] = desc
|
||||
for line in result.split( b"\n" ) :
|
||||
if line[:3] == b"UPS" :
|
||||
ups, desc = line[4:-1].split( b'"' )
|
||||
ups_list[ ups.replace( b" ", b"" ) ] = desc
|
||||
|
||||
return( ups_list )
|
||||
|
||||
|
|
@ -148,19 +153,19 @@ available vars.
|
|||
if self.__debug :
|
||||
print( "[DEBUG] GetUPSVars called..." )
|
||||
|
||||
self.__srv_handler.write( "LIST VAR %s\n" % ups )
|
||||
result = self.__srv_handler.read_until( "\n" )
|
||||
if result != "BEGIN LIST VAR %s\n" % ups :
|
||||
raise PyNUTError( result.replace( "\n", "" ) )
|
||||
self.__srv_handler.write( ("LIST VAR %s\n" % ups).encode('ascii') )
|
||||
result = self.__srv_handler.read_until( b"\n" )
|
||||
if result != ("BEGIN LIST VAR %s\n" % ups).encode('ascii') :
|
||||
raise PyNUTError( result.replace( b"\n", b"" ) )
|
||||
|
||||
ups_vars = {}
|
||||
result = self.__srv_handler.read_until( "END LIST VAR %s\n" % ups )
|
||||
offset = len( "VAR %s " % ups )
|
||||
end_offset = 0 - ( len( "END LIST VAR %s\n" % ups ) + 1 )
|
||||
result = self.__srv_handler.read_until( ("END LIST VAR %s\n" % ups).encode('ascii') )
|
||||
offset = len( ("VAR %s " % ups ).encode('ascii') )
|
||||
end_offset = 0 - ( len( ("END LIST VAR %s\n" % ups).encode('ascii') ) + 1 )
|
||||
|
||||
for current in result[:end_offset].split( "\n" ) :
|
||||
var = current[ offset: ].split( '"' )[0].replace( " ", "" )
|
||||
data = current[ offset: ].split( '"' )[1]
|
||||
for current in result[:end_offset].split( b"\n" ) :
|
||||
var = current[ offset: ].split( b'"' )[0].replace( b" ", b"" )
|
||||
data = current[ offset: ].split( b'"' )[1]
|
||||
ups_vars[ var ] = data
|
||||
|
||||
return( ups_vars )
|
||||
|
|
@ -174,28 +179,28 @@ of the command as value
|
|||
if self.__debug :
|
||||
print( "[DEBUG] GetUPSCommands called..." )
|
||||
|
||||
self.__srv_handler.write( "LIST CMD %s\n" % ups )
|
||||
result = self.__srv_handler.read_until( "\n" )
|
||||
if result != "BEGIN LIST CMD %s\n" % ups :
|
||||
raise PyNUTError( result.replace( "\n", "" ) )
|
||||
self.__srv_handler.write( ("LIST CMD %s\n" % ups).encode('ascii') )
|
||||
result = self.__srv_handler.read_until( b"\n" )
|
||||
if result != ("BEGIN LIST CMD %s\n" % ups).encode('ascii') :
|
||||
raise PyNUTError( result.replace( b"\n", b"" ) )
|
||||
|
||||
ups_cmds = {}
|
||||
result = self.__srv_handler.read_until( "END LIST CMD %s\n" % ups )
|
||||
offset = len( "CMD %s " % ups )
|
||||
end_offset = 0 - ( len( "END LIST CMD %s\n" % ups ) + 1 )
|
||||
result = self.__srv_handler.read_until( ("END LIST CMD %s\n" % ups).encode('ascii') )
|
||||
offset = len( ("CMD %s " % ups).encode('ascii') )
|
||||
end_offset = 0 - ( len( ("END LIST CMD %s\n" % ups).encode('ascii') ) + 1 )
|
||||
|
||||
for current in result[:end_offset].split( "\n" ) :
|
||||
var = current[ offset: ].split( '"' )[0].replace( " ", "" )
|
||||
for current in result[:end_offset].split( b"\n" ) :
|
||||
var = current[ offset: ].split( b'"' )[0].replace( b" ", b"" )
|
||||
|
||||
# For each var we try to get the available description
|
||||
try :
|
||||
self.__srv_handler.write( "GET CMDDESC %s %s\n" % ( ups, var ) )
|
||||
temp = self.__srv_handler.read_until( "\n" )
|
||||
if temp[:7] != "CMDDESC" :
|
||||
self.__srv_handler.write( ("GET CMDDESC %s %s\n" % ( ups, var )).encode('ascii') )
|
||||
temp = self.__srv_handler.read_until( b"\n" )
|
||||
if temp[:7] != b"CMDDESC" :
|
||||
raise PyNUTError
|
||||
else :
|
||||
off = len( "CMDDESC %s %s " % ( ups, var ) )
|
||||
desc = temp[off:-1].split('"')[1]
|
||||
off = len( ("CMDDESC %s %s " % ( ups, var )).encode('ascii') )
|
||||
desc = temp[off:-1].split(b'"')[1]
|
||||
except :
|
||||
desc = var
|
||||
|
||||
|
|
@ -211,20 +216,20 @@ The result is presented as a dictionary containing 'key->val' pairs
|
|||
if self.__debug :
|
||||
print( "[DEBUG] GetUPSVars from '%s'..." % ups )
|
||||
|
||||
self.__srv_handler.write( "LIST RW %s\n" % ups )
|
||||
result = self.__srv_handler.read_until( "\n" )
|
||||
if ( result != "BEGIN LIST RW %s\n" % ups ) :
|
||||
raise PyNUTError( result.replace( "\n", "" ) )
|
||||
self.__srv_handler.write( ("LIST RW %s\n" % ups).encode('ascii') )
|
||||
result = self.__srv_handler.read_until( b"\n" )
|
||||
if ( result != ("BEGIN LIST RW %s\n" % ups).encode('ascii') ) :
|
||||
raise PyNUTError( result.replace( b"\n", b"" ) )
|
||||
|
||||
result = self.__srv_handler.read_until( "END LIST RW %s\n" % ups )
|
||||
offset = len( "VAR %s" % ups )
|
||||
end_offset = 0 - ( len( "END LIST RW %s\n" % ups ) + 1 )
|
||||
result = self.__srv_handler.read_until( ("END LIST RW %s\n" % ups).encode('ascii') )
|
||||
offset = len( ("VAR %s" % ups).encode('ascii') )
|
||||
end_offset = 0 - ( len( ("END LIST RW %s\n" % ups).encode('ascii') ) + 1 )
|
||||
rw_vars = {}
|
||||
|
||||
try :
|
||||
for current in result[:end_offset].split( "\n" ) :
|
||||
var = current[ offset: ].split( '"' )[0].replace( " ", "" )
|
||||
data = current[ offset: ].split( '"' )[1]
|
||||
for current in result[:end_offset].split( b"\n" ) :
|
||||
var = current[ offset: ].split( b'"' )[0].replace( b" ", b"" )
|
||||
data = current[ offset: ].split( b'"' )[1]
|
||||
rw_vars[ var ] = data
|
||||
|
||||
except :
|
||||
|
|
@ -239,9 +244,9 @@ The variable must be a writable value (cf GetRWVars) and you must have the prope
|
|||
rights to set it (maybe login/password).
|
||||
"""
|
||||
|
||||
self.__srv_handler.write( "SET VAR %s %s %s\n" % ( ups, var, value ) )
|
||||
result = self.__srv_handler.read_until( "\n" )
|
||||
if ( result == "OK\n" ) :
|
||||
self.__srv_handler.write( ("SET VAR %s %s %s\n" % ( ups, var, value )).encode('ascii') )
|
||||
result = self.__srv_handler.read_until( b"\n" )
|
||||
if ( result == b"OK\n" ) :
|
||||
return( "OK" )
|
||||
else :
|
||||
raise PyNUTError( result )
|
||||
|
|
@ -255,35 +260,43 @@ Returns OK on success or raises an error
|
|||
if self.__debug :
|
||||
print( "[DEBUG] RunUPSCommand called..." )
|
||||
|
||||
self.__srv_handler.write( "INSTCMD %s %s\n" % ( ups, command ) )
|
||||
result = self.__srv_handler.read_until( "\n" )
|
||||
if ( result == "OK\n" ) :
|
||||
self.__srv_handler.write( ("INSTCMD %s %s\n" % ( ups, command )).encode('ascii') )
|
||||
result = self.__srv_handler.read_until( b"\n" )
|
||||
if ( result == b"OK\n" ) :
|
||||
return( "OK" )
|
||||
else :
|
||||
raise PyNUTError( result.replace( "\n", "" ) )
|
||||
raise PyNUTError( result.replace( b"\n", b"" ) )
|
||||
|
||||
def FSD( self, ups="") :
|
||||
""" Send FSD command
|
||||
|
||||
Returns OK on success or raises an error
|
||||
|
||||
NOTE: API changed since NUT 2.8.0 to replace MASTER with PRIMARY
|
||||
(and backwards-compatible alias handling)
|
||||
"""
|
||||
|
||||
if self.__debug :
|
||||
print( "[DEBUG] MASTER called..." )
|
||||
print( "[DEBUG] PRIMARY called..." )
|
||||
|
||||
self.__srv_handler.write( "MASTER %s\n" % ups )
|
||||
result = self.__srv_handler.read_until( "\n" )
|
||||
if ( result != "OK MASTER-GRANTED\n" ) :
|
||||
raise PyNUTError( ( "Master level function are not available", "" ) )
|
||||
self.__srv_handler.write( ("PRIMARY %s\n" % ups).encode('ascii') )
|
||||
result = self.__srv_handler.read_until( b"\n" )
|
||||
if ( result != b"OK PRIMARY-GRANTED\n" ) :
|
||||
if self.__debug :
|
||||
print( "[DEBUG] Retrying: MASTER called..." )
|
||||
self.__srv_handler.write( ("MASTER %s\n" % ups).encode('ascii') )
|
||||
result = self.__srv_handler.read_until( b"\n" )
|
||||
if ( result != b"OK MASTER-GRANTED\n" ) :
|
||||
raise PyNUTError( ( "Primary level functions are not available", "" ) )
|
||||
|
||||
if self.__debug :
|
||||
print( "[DEBUG] FSD called..." )
|
||||
self.__srv_handler.write( "FSD %s\n" % ups )
|
||||
result = self.__srv_handler.read_until( "\n" )
|
||||
if ( result == "OK FSD-SET\n" ) :
|
||||
self.__srv_handler.write( ("FSD %s\n" % ups).encode('ascii') )
|
||||
result = self.__srv_handler.read_until( b"\n" )
|
||||
if ( result == b"OK FSD-SET\n" ) :
|
||||
return( "OK" )
|
||||
else :
|
||||
raise PyNUTError( result.replace( "\n", "" ) )
|
||||
raise PyNUTError( result.replace( b"\n", b"" ) )
|
||||
|
||||
def help(self) :
|
||||
""" Send HELP command
|
||||
|
|
@ -292,8 +305,8 @@ Returns OK on success or raises an error
|
|||
if self.__debug :
|
||||
print( "[DEBUG] HELP called..." )
|
||||
|
||||
self.__srv_handler.write( "HELP\n")
|
||||
return self.__srv_handler.read_until( "\n" )
|
||||
self.__srv_handler.write( b"HELP\n" )
|
||||
return self.__srv_handler.read_until( b"\n" )
|
||||
|
||||
def ver(self) :
|
||||
""" Send VER command
|
||||
|
|
@ -302,8 +315,8 @@ Returns OK on success or raises an error
|
|||
if self.__debug :
|
||||
print( "[DEBUG] VER called..." )
|
||||
|
||||
self.__srv_handler.write( "VER\n")
|
||||
return self.__srv_handler.read_until( "\n" )
|
||||
self.__srv_handler.write( b"VER\n" )
|
||||
return self.__srv_handler.read_until( b"\n" )
|
||||
|
||||
def ListClients( self, ups = None ) :
|
||||
""" Returns the list of connected clients from the NUT server
|
||||
|
|
@ -317,20 +330,20 @@ The result is a dictionary containing 'key->val' pairs of 'UPSName' and a list o
|
|||
raise PyNUTError( "%s is not a valid UPS" % ups )
|
||||
|
||||
if ups:
|
||||
self.__srv_handler.write( "LIST CLIENTS %s\n" % ups)
|
||||
self.__srv_handler.write( ("LIST CLIENTS %s\n" % ups).encode('ascii') )
|
||||
else:
|
||||
self.__srv_handler.write( "LIST CLIENTS\n" )
|
||||
result = self.__srv_handler.read_until( "\n" )
|
||||
if result != "BEGIN LIST CLIENTS\n" :
|
||||
raise PyNUTError( result.replace( "\n", "" ) )
|
||||
self.__srv_handler.write( b"LIST CLIENTS\n" )
|
||||
result = self.__srv_handler.read_until( b"\n" )
|
||||
if result != b"BEGIN LIST CLIENTS\n" :
|
||||
raise PyNUTError( result.replace( b"\n", b"" ) )
|
||||
|
||||
result = self.__srv_handler.read_until( "END LIST CLIENTS\n" )
|
||||
result = self.__srv_handler.read_until( b"END LIST CLIENTS\n" )
|
||||
ups_list = {}
|
||||
|
||||
for line in result.split( "\n" ):
|
||||
if line[:6] == "CLIENT" :
|
||||
host, ups = line[7:].split(' ')
|
||||
ups.replace(' ', '')
|
||||
for line in result.split( b"\n" ):
|
||||
if line[:6] == b"CLIENT" :
|
||||
host, ups = line[7:].split(b' ')
|
||||
ups.replace(b' ', b'')
|
||||
if not ups in ups_list:
|
||||
ups_list[ups] = []
|
||||
ups_list[ups].append(host)
|
||||
|
|
@ -1,22 +1,31 @@
|
|||
#!/usr/bin/env python
|
||||
#!@PYTHON@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# This source code is provided for testing/debuging purpose ;)
|
||||
|
||||
import PyNUT
|
||||
import sys
|
||||
import os
|
||||
|
||||
if __name__ == "__main__" :
|
||||
NUT_PORT = int(os.getenv('NUT_PORT', '3493'))
|
||||
NUT_USER = os.getenv('NUT_USER', None)
|
||||
NUT_PASS = os.getenv('NUT_PASS', None)
|
||||
|
||||
print( "PyNUTClient test..." )
|
||||
nut = PyNUT.PyNUTClient( debug=True )
|
||||
#nut = PyNUT.PyNUTClient( login="upsadmin", password="upsadmin", debug=True )
|
||||
#nut = PyNUT.PyNUTClient( debug=True, port=NUT_PORT )
|
||||
nut = PyNUT.PyNUTClient( login=NUT_USER, password=NUT_PASS, debug=True, port=NUT_PORT )
|
||||
#nut = PyNUT.PyNUTClient( login="upsadmin", password="upsadmin", debug=True, port=NUT_PORT )
|
||||
|
||||
print( 80*"-" + "\nTesting 'GetUPSList' :")
|
||||
result = nut.GetUPSList( )
|
||||
print( "\033[01;33m%s\033[0m\n" % result )
|
||||
|
||||
print( 80*"-" + "\nTesting 'GetUPSVars' :")
|
||||
# [dummy]
|
||||
# driver = dummy-ups
|
||||
# desc = "Test device"
|
||||
# port = /src/nut/data/evolution500.seq
|
||||
print( 80*"-" + "\nTesting 'GetUPSVars' for 'dummy' (should be registered in upsd.conf) :")
|
||||
result = nut.GetUPSVars( "dummy" )
|
||||
print( "\033[01;33m%s\033[0m\n" % result )
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue