add BlitzTUI files (based on PyQT5)
1
.gitignore
vendored
@ -1,4 +1,5 @@
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
home.admin/.DS_Store
|
home.admin/.DS_Store
|
||||||
*.log
|
*.log
|
||||||
|
*.pyc
|
||||||
__pycache__
|
__pycache__
|
||||||
|
@ -599,6 +599,10 @@ echo "to switch between python2/3: sudo update-alternatives --config python"
|
|||||||
sudo apt-get -f -y install virtualenv
|
sudo apt-get -f -y install virtualenv
|
||||||
sudo chown -R admin /home/admin
|
sudo chown -R admin /home/admin
|
||||||
sudo -u admin bash -c "cd; virtualenv python-env-lnd; source /home/admin/python-env-lnd/bin/activate; pip install grpcio grpcio-tools googleapis-common-protos pathlib2"
|
sudo -u admin bash -c "cd; virtualenv python-env-lnd; source /home/admin/python-env-lnd/bin/activate; pip install grpcio grpcio-tools googleapis-common-protos pathlib2"
|
||||||
|
|
||||||
|
# This Python3 virtualenv includes the site-packages because access to the PyQt5
|
||||||
|
# libs - which are installed system-wide (via apt-get) - is needed for TouchUI.
|
||||||
|
sudo -u admin bash -c "cd; virtualenv -p python3 --system-site-packages python3-env-lnd"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
|
@ -1,161 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# 00infoLCDTK.py
|
|
||||||
#
|
|
||||||
# called by #
|
|
||||||
# /home/pi/autostart.sh
|
|
||||||
# dev/test/run with:
|
|
||||||
# sudo -i -u pi DISPLAY=:0.0 /usr/bin/python3 /home/admin/00infoLCDTK.py
|
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import json
|
|
||||||
import logging
|
|
||||||
import logging.config
|
|
||||||
import tkinter as tk
|
|
||||||
|
|
||||||
COLOR = "black"
|
|
||||||
WINFO = None
|
|
||||||
|
|
||||||
log = logging.getLogger()
|
|
||||||
|
|
||||||
|
|
||||||
def setup_logging(default_path='00infoLCDw.json'):
|
|
||||||
"""Setup logging configuration"""
|
|
||||||
path = default_path
|
|
||||||
if os.path.exists(path):
|
|
||||||
with open(path, 'rt') as f:
|
|
||||||
config = json.load(f)
|
|
||||||
logging.config.dictConfig(config)
|
|
||||||
else: # if $default_path does not exist use the following default log setup
|
|
||||||
default_config_as_json = """
|
|
||||||
{
|
|
||||||
"version": 1,
|
|
||||||
"disable_existing_loggers": false,
|
|
||||||
"formatters": {
|
|
||||||
"simple": {
|
|
||||||
"format": "%(asctime)s - %(levelname)s - %(message)s"
|
|
||||||
},
|
|
||||||
"extended": {
|
|
||||||
"format": "%(asctime)s - %(name)s - %(levelname)s - %(module)s:%(lineno)d - %(message)s"
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
"handlers": {
|
|
||||||
"console": {
|
|
||||||
"class": "logging.StreamHandler",
|
|
||||||
"level": "INFO",
|
|
||||||
"formatter": "simple",
|
|
||||||
"stream": "ext://sys.stdout"
|
|
||||||
},
|
|
||||||
|
|
||||||
"file_handler": {
|
|
||||||
"class": "logging.handlers.RotatingFileHandler",
|
|
||||||
"level": "DEBUG",
|
|
||||||
"formatter": "extended",
|
|
||||||
"filename": "00infoLCDTK.log",
|
|
||||||
"maxBytes": 10485760,
|
|
||||||
"backupCount": 0,
|
|
||||||
"encoding": "utf8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
"loggers": {
|
|
||||||
"infoblitz": {
|
|
||||||
"level": "INFO",
|
|
||||||
"handlers": ["console", "file_handler"],
|
|
||||||
"propagate": "no"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
"root": {
|
|
||||||
"level": "INFO",
|
|
||||||
"handlers": ["console", "file_handler"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
config = json.loads(default_config_as_json)
|
|
||||||
logging.config.dictConfig(config)
|
|
||||||
|
|
||||||
|
|
||||||
def callback_b1():
|
|
||||||
global WINFO
|
|
||||||
log.info("clicked b1 - no action yet (placeholder)")
|
|
||||||
#if sys.platform != "win32":
|
|
||||||
# os.system("xterm -fn fixed -into %d +sb -hold /home/admin/00infoLCD.sh &" % WINFO)
|
|
||||||
|
|
||||||
|
|
||||||
def callback_b2():
|
|
||||||
global WINFO
|
|
||||||
log.info("clicked b2 - no action yet (placeholder)")
|
|
||||||
#if sys.platform != "win32":
|
|
||||||
# os.system("xterm -fn fixed -into %d +sb -hold /home/admin/XXbutton2.sh &" % WINFO)
|
|
||||||
|
|
||||||
def callback_b3():
|
|
||||||
global WINFO
|
|
||||||
log.info("clicked b3 - no action yet")
|
|
||||||
#if sys.platform != "win32":
|
|
||||||
# os.system("xterm -fn fixed -into %d +sb -hold /home/admin/XXbutton3.sh &" % WINFO)
|
|
||||||
|
|
||||||
def callback_b4():
|
|
||||||
global WINFO
|
|
||||||
log.info("clicked b4")
|
|
||||||
if sys.platform != "win32":
|
|
||||||
os.system("xterm -fn fixed -into %d +sb -hold /home/admin/XXshutdown.sh &" % WINFO)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
global WINFO
|
|
||||||
setup_logging()
|
|
||||||
log.info("Starting 00infoLCDTK.py")
|
|
||||||
|
|
||||||
# LCD root
|
|
||||||
root = tk.Tk()
|
|
||||||
root.config(bg=COLOR)
|
|
||||||
root.overrideredirect(1)
|
|
||||||
root.geometry("480x320+0+0")
|
|
||||||
root.title("RaspiBlitz")
|
|
||||||
|
|
||||||
# but LCD on canvas
|
|
||||||
entry = tk.Entry(root)
|
|
||||||
entry.config(bg=COLOR, highlightbackground=COLOR)
|
|
||||||
entry.pack(side="bottom", fill="x")
|
|
||||||
|
|
||||||
# button frame
|
|
||||||
frame1 = tk.Frame(entry, width=80, background="black")
|
|
||||||
frame1.pack(side="left", fill="both", expand=True)
|
|
||||||
|
|
||||||
# button 1 - no action yet (placeholder)
|
|
||||||
button1 = tk.Button(frame1, text='\u002d', fg='black', command=callback_b1, height = 1, width = 1)
|
|
||||||
button1.pack(pady=24)
|
|
||||||
|
|
||||||
# button 2 - no action yet (placeholder)
|
|
||||||
button2 = tk.Button(frame1, text='\u002d', fg='black', command=callback_b2, height = 1, width = 1)
|
|
||||||
button2.pack(pady=24)
|
|
||||||
|
|
||||||
# button 3 - no action yet (placeholder)
|
|
||||||
button3 = tk.Button(frame1, text='\u002d', fg='black', command=callback_b3, height = 1, width = 1)
|
|
||||||
button3.pack(pady=24)
|
|
||||||
#label3 = tk.Label(frame1, text='1.3', bg=COLOR, fg='white')
|
|
||||||
#label3.pack(pady=24)
|
|
||||||
|
|
||||||
# button 4 - no action yet (power down)
|
|
||||||
button4 = tk.Button(frame1, text='\N{BLACK CIRCLE}', fg='red', command=callback_b4, height = 1, width = 1)
|
|
||||||
button4.pack(pady=24)
|
|
||||||
|
|
||||||
# content frame
|
|
||||||
frame2 = tk.Frame(entry, width=400, background="grey")
|
|
||||||
frame2.pack(side="right", fill="both", expand=True)
|
|
||||||
|
|
||||||
# run terminal in
|
|
||||||
WINFO = frame2.winfo_id()
|
|
||||||
if sys.platform != "win32":
|
|
||||||
os.system("xterm -fn fixed -into %d +sb -hold /home/admin/00infoLCD.sh &" % WINFO)
|
|
||||||
|
|
||||||
# run
|
|
||||||
root.mainloop()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
3
home.admin/BlitzTUI/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
BlitzTUI.egg-info/*
|
||||||
|
build/*
|
||||||
|
dist/*
|
30
home.admin/BlitzTUI/CHANGELOG.md
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [0.41.0] - 2019-11-15
|
||||||
|
### Added
|
||||||
|
- reduce default channel check interval to 40
|
||||||
|
- increase invoice monitor time to 1 hour
|
||||||
|
|
||||||
|
## [0.39.0] - 2019-11-04
|
||||||
|
### Added
|
||||||
|
- fix logging
|
||||||
|
- update blitz.touchscreen.sh scripts
|
||||||
|
|
||||||
|
## [0.36.0] - 2019-11-03
|
||||||
|
### Added
|
||||||
|
- require at least gRPC (grpcio) version 1.24.3 (to address atomic_exchange_8 issue)
|
||||||
|
- fix issue on "not-default" setup (not bitcoin/mainnet)
|
||||||
|
|
||||||
|
## [0.29.0] - 2019-11-02
|
||||||
|
### Added
|
||||||
|
- almost all must-have features have been implemented
|
||||||
|
|
||||||
|
|
||||||
|
## [0.22.2] - 2019-10-27
|
||||||
|
### Added
|
||||||
|
- initial creation
|
21
home.admin/BlitzTUI/LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2018-2019 The RaspiBlitz developers
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
1
home.admin/BlitzTUI/MANIFEST.in
Normal file
@ -0,0 +1 @@
|
|||||||
|
include CHANGELOG.md
|
27
home.admin/BlitzTUI/Makefile
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# Makefile
|
||||||
|
|
||||||
|
build:
|
||||||
|
python setup.py sdist bdist_wheel
|
||||||
|
|
||||||
|
build-ui:
|
||||||
|
pyuic5 -x --import-from "." -o blitztui/ui/qcode.py designer/qcode.ui
|
||||||
|
pyuic5 -x --import-from "." -o blitztui/ui/home.py designer/home.ui
|
||||||
|
pyuic5 -x --import-from "." -o blitztui/ui/off.py designer/off.ui
|
||||||
|
pyuic5 -x --import-from "." -o blitztui/ui/invoice.py designer/invoice.ui
|
||||||
|
pyrcc5 -o blitztui/ui/resources_rc.py resources.qrc
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf .eggs .tox .coverage .coverage.data .cache build
|
||||||
|
rm -rf blitz-tui.log BlitzTUI.egg-info
|
||||||
|
find ./ -iname "*.pyc" -delete
|
||||||
|
find ./ -type d -iname "__pycache__" -delete
|
||||||
|
|
||||||
|
test:
|
||||||
|
tox
|
||||||
|
|
||||||
|
upload:
|
||||||
|
twine upload --skip-existing dist/* -r pypi
|
||||||
|
|
||||||
|
upload-test:
|
||||||
|
twine upload --skip-existing dist/* -r pypitest
|
||||||
|
|
65
home.admin/BlitzTUI/README.md
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
# BlitzTUI
|
||||||
|
|
||||||
|
[](https://badge.fury.io/)
|
||||||
|
[](https://shields.io/)
|
||||||
|
[](https://shields.io/)
|
||||||
|
|
||||||
|
BlitzTUI is a part of the RaspiBlitz project and implements a Touch User Interface in PyQt5.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
|
||||||
|
### Prerequisite
|
||||||
|
|
||||||
|
QT is needed. Please install PyQt5 (see below).
|
||||||
|
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
|
||||||
|
#### Debian/Ubuntu (and similar)
|
||||||
|
|
||||||
|
```
|
||||||
|
apt-get install python3-pyqt5
|
||||||
|
```
|
||||||
|
|
||||||
|
#### PIP
|
||||||
|
|
||||||
|
The PIP dependencies are installed automatically - this listing is "FYI"
|
||||||
|
|
||||||
|
* grpcio
|
||||||
|
* googleapis-common-protos
|
||||||
|
* inotify
|
||||||
|
* psutil
|
||||||
|
* pyqtspinner
|
||||||
|
* qrcode
|
||||||
|
|
||||||
|
|
||||||
|
### Install BlitzTUI
|
||||||
|
|
||||||
|
```
|
||||||
|
pip install BlitzTUI
|
||||||
|
```
|
||||||
|
|
||||||
|
**or** consider using a virtual environment
|
||||||
|
|
||||||
|
```
|
||||||
|
virtualenv -p python3 --system-site-packages venv
|
||||||
|
source venv/bin/activate
|
||||||
|
pip install BlitzTUI
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Error Messages
|
||||||
|
|
||||||
|
For now the following warning/error/info messages can be ignored. If anybody knows how to suppress
|
||||||
|
or fix them please send a PR (or open an issue).
|
||||||
|
|
||||||
|
```
|
||||||
|
libEGL warning: DRI2: failed to authenticate
|
||||||
|
QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '/tmp/runtime-pi'
|
||||||
|
2019-11-02 20:01:21,504 - root - INFO - main:214 - /usr/bin/xterm: cannot load font "-Misc-Fixed-medium-R-*-*-13-120-75-75-C-120-ISO10646-1"
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[MIT License](http://en.wikipedia.org/wiki/MIT_License)
|
9
home.admin/BlitzTUI/blitztui/__init__.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import logging
|
||||||
|
from blitztui.version import __version__
|
||||||
|
from blitztui.file_logger import setup_logging
|
||||||
|
|
||||||
|
log = logging.getLogger()
|
||||||
|
setup_logging()
|
||||||
|
log.info("Starting BlitzTUI v{}".format(__version__))
|
273
home.admin/BlitzTUI/blitztui/client.py
Normal file
@ -0,0 +1,273 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import base64
|
||||||
|
import codecs
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from os.path import isfile
|
||||||
|
|
||||||
|
import grpc
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
IS_WIN32_ENV = sys.platform == "win32"
|
||||||
|
|
||||||
|
if IS_WIN32_ENV:
|
||||||
|
cur_path = os.path.abspath(os.path.curdir)
|
||||||
|
config_script1 = os.path.join(cur_path, "home.admin", "config.scripts")
|
||||||
|
config_script2 = os.path.abspath(os.path.join(cur_path, "..", "..", "home.admin", "config.scripts"))
|
||||||
|
sys.path.insert(1, config_script1)
|
||||||
|
sys.path.insert(1, config_script2)
|
||||||
|
else:
|
||||||
|
sys.path.insert(1, '/home/admin/config.scripts')
|
||||||
|
|
||||||
|
from lndlibs import rpc_pb2 as ln
|
||||||
|
try:
|
||||||
|
from lndlibs import rpc_pb2_grpc as lnrpc
|
||||||
|
except ModuleNotFoundError as err:
|
||||||
|
log.error("ModuleNotFoundError - most likely an issue with incompatible Python3 import.\n"
|
||||||
|
"Please run the following two lines to fix this: \n"
|
||||||
|
"\n"
|
||||||
|
"sed -i -E '1 a from __future__ import absolute_import' "
|
||||||
|
"/home/admin/config.scripts/lndlibs/rpc_pb2_grpc.py\n"
|
||||||
|
"sed -i -E 's/^(import.*_pb2)/from . \\1/' /home/admin/config.scripts/lndlibs/rpc_pb2_grpc.py")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if not IS_WIN32_ENV:
|
||||||
|
import psutil
|
||||||
|
|
||||||
|
MACAROON_LIST = ["admin", "readonly", "invoice"]
|
||||||
|
|
||||||
|
|
||||||
|
class AdminStub(lnrpc.LightningStub):
|
||||||
|
def __init__(self, network="bitcoin", chain="main"):
|
||||||
|
self.channel = get_rpc_channel(macaroon_path=build_macaroon_path("admin", network=network, chain=chain))
|
||||||
|
super().__init__(self.channel)
|
||||||
|
|
||||||
|
|
||||||
|
class ReadOnlyStub(lnrpc.LightningStub):
|
||||||
|
def __init__(self, network="bitcoin", chain="main"):
|
||||||
|
self.channel = get_rpc_channel(macaroon_path=build_macaroon_path("readonly", network=network, chain=chain))
|
||||||
|
super().__init__(self.channel)
|
||||||
|
|
||||||
|
|
||||||
|
class InvoiceStub(lnrpc.LightningStub):
|
||||||
|
def __init__(self, network="bitcoin", chain="main"):
|
||||||
|
self.channel = get_rpc_channel(macaroon_path=build_macaroon_path("invoice", network=network, chain=chain))
|
||||||
|
super().__init__(self.channel)
|
||||||
|
|
||||||
|
|
||||||
|
def convert_r_hash(r_hash):
|
||||||
|
""" convert_r_hash
|
||||||
|
|
||||||
|
>>> convert_r_hash("+eMo9YTaZIjkJacclb6LYUocwa0q7cgVOBPf/0aclYQ=")
|
||||||
|
'f9e328f584da6488e425a71c95be8b614a1cc1ad2aedc8153813dfff469c9584'
|
||||||
|
|
||||||
|
"""
|
||||||
|
r_hash_bytes = codecs.decode(r_hash.encode(), 'base64')
|
||||||
|
r_hash_hex_bytes = codecs.encode(r_hash_bytes, 'hex')
|
||||||
|
return r_hash_hex_bytes.decode()
|
||||||
|
|
||||||
|
|
||||||
|
def convert_r_hash_hex(r_hash_hex):
|
||||||
|
""" convert_r_hash_hex
|
||||||
|
|
||||||
|
>>> convert_r_hash_hex("f9e328f584da6488e425a71c95be8b614a1cc1ad2aedc8153813dfff469c9584")
|
||||||
|
'+eMo9YTaZIjkJacclb6LYUocwa0q7cgVOBPf/0aclYQ='
|
||||||
|
|
||||||
|
"""
|
||||||
|
r_hash = codecs.decode(r_hash_hex, 'hex')
|
||||||
|
r_hash_b64_bytes = base64.b64encode(r_hash)
|
||||||
|
return r_hash_b64_bytes.decode()
|
||||||
|
|
||||||
|
|
||||||
|
def convert_r_hash_hex_bytes(r_hash_hex_bytes):
|
||||||
|
""" convert_r_hash_hex_bytes
|
||||||
|
|
||||||
|
>>> convert_r_hash_hex_bytes(b'\xf9\xe3(\xf5\x84\xdad\x88\xe4%\xa7\x1c\x95\xbe\x8baJ\x1c\xc1\xad*\xed\xc8\x158\x13\xdf\xffF\x9c\x95\x84')
|
||||||
|
'f9e328f584da6488e425a71c95be8b614a1cc1ad2aedc8153813dfff469c9584'
|
||||||
|
|
||||||
|
"""
|
||||||
|
r_hash_hex_bytes = codecs.encode(r_hash_hex_bytes, 'hex')
|
||||||
|
return r_hash_hex_bytes.decode()
|
||||||
|
|
||||||
|
|
||||||
|
def get_rpc_channel(host="localhost", port="10009", cert_path=None, macaroon_path=None):
|
||||||
|
if not macaroon_path:
|
||||||
|
raise Exception("need to specify a macaroon path!")
|
||||||
|
|
||||||
|
def metadata_callback(context, callback):
|
||||||
|
# for more info see grpc docs
|
||||||
|
callback([('macaroon', macaroon)], None)
|
||||||
|
|
||||||
|
# Due to updated ECDSA generated tls.cert we need to let gprc know that
|
||||||
|
# we need to use that cipher suite otherwise there will be a handshake
|
||||||
|
# error when we communicate with the lnd rpc server.
|
||||||
|
os.environ["GRPC_SSL_CIPHER_SUITES"] = 'HIGH+ECDSA'
|
||||||
|
|
||||||
|
if not cert_path:
|
||||||
|
cert_path = os.path.expanduser('~/.lnd/tls.cert')
|
||||||
|
|
||||||
|
assert isfile(cert_path) and os.access(cert_path, os.R_OK), \
|
||||||
|
"File {} doesn't exist or isn't readable".format(cert_path)
|
||||||
|
cert = open(cert_path, 'rb').read()
|
||||||
|
|
||||||
|
with open(macaroon_path, 'rb') as f:
|
||||||
|
macaroon_bytes = f.read()
|
||||||
|
macaroon = codecs.encode(macaroon_bytes, 'hex')
|
||||||
|
|
||||||
|
# build ssl credentials using the cert the same as before
|
||||||
|
cert_creds = grpc.ssl_channel_credentials(cert)
|
||||||
|
|
||||||
|
# now build meta data credentials
|
||||||
|
auth_creds = grpc.metadata_call_credentials(metadata_callback)
|
||||||
|
|
||||||
|
# combine the cert credentials and the macaroon auth credentials
|
||||||
|
# such that every call is properly encrypted and authenticated
|
||||||
|
combined_creds = grpc.composite_channel_credentials(cert_creds, auth_creds)
|
||||||
|
|
||||||
|
# finally pass in the combined credentials when creating a channel
|
||||||
|
return grpc.secure_channel('{}:{}'.format(host, port), combined_creds)
|
||||||
|
|
||||||
|
|
||||||
|
def build_macaroon_path(name=None, network="bitcoin", chain="main"):
|
||||||
|
if not name.lower() in MACAROON_LIST:
|
||||||
|
raise Exception("name must be one of: {}".format(", ".join(MACAROON_LIST)))
|
||||||
|
|
||||||
|
macaroon_path = os.path.expanduser('~/.lnd/data/chain/{}/{}net/{}.macaroon'.format(network, chain, name.lower()))
|
||||||
|
assert isfile(macaroon_path) and os.access(macaroon_path, os.R_OK), \
|
||||||
|
"File {} doesn't exist or isn't readable".format(macaroon_path)
|
||||||
|
|
||||||
|
return macaroon_path
|
||||||
|
|
||||||
|
|
||||||
|
def check_lnd(stub, proc_name="lnd", rpc_listen_ports=None):
|
||||||
|
if not rpc_listen_ports:
|
||||||
|
rpc_listen_ports = [10009]
|
||||||
|
|
||||||
|
pid_ok = False
|
||||||
|
listen_ok = False
|
||||||
|
unlocked = False
|
||||||
|
synced_to_chain = False
|
||||||
|
synced_to_graph = False
|
||||||
|
|
||||||
|
if IS_WIN32_ENV:
|
||||||
|
return pid_ok, listen_ok, unlocked, synced_to_chain, synced_to_graph
|
||||||
|
|
||||||
|
if not [p.info for p in psutil.process_iter(attrs=['pid', 'name']) if proc_name in p.info['name']]:
|
||||||
|
return pid_ok, listen_ok, unlocked, synced_to_chain, synced_to_graph
|
||||||
|
else:
|
||||||
|
pid_ok = True
|
||||||
|
|
||||||
|
if not [net_con for net_con in psutil.net_connections(kind='inet')
|
||||||
|
if (net_con.status == psutil.CONN_LISTEN and net_con.laddr[1] in rpc_listen_ports)]:
|
||||||
|
return pid_ok, listen_ok, unlocked, synced_to_chain, synced_to_graph
|
||||||
|
else:
|
||||||
|
listen_ok = True
|
||||||
|
|
||||||
|
try:
|
||||||
|
get_info = stub.GetInfo(ln.GetInfoRequest())
|
||||||
|
unlocked = True
|
||||||
|
synced_to_chain = get_info.synced_to_chain
|
||||||
|
synced_to_graph = get_info.synced_to_graph
|
||||||
|
|
||||||
|
except grpc.RpcError as err:
|
||||||
|
if err._state.__dict__['code'] == grpc.StatusCode.UNIMPLEMENTED:
|
||||||
|
log.debug("wallet is 'locked'")
|
||||||
|
else:
|
||||||
|
log.warning("an unknown RpcError occurred")
|
||||||
|
log.warning(err)
|
||||||
|
|
||||||
|
except Exception as err:
|
||||||
|
log.warning("an error occurred: {}".format(err))
|
||||||
|
|
||||||
|
return pid_ok, listen_ok, unlocked, synced_to_chain, synced_to_graph
|
||||||
|
|
||||||
|
|
||||||
|
def check_lnd_channels(stub):
|
||||||
|
"""let's assume that check_lnd() was called just before calling this"""
|
||||||
|
total_active_channels = 0
|
||||||
|
total_remote_balance_sat = 0
|
||||||
|
|
||||||
|
try:
|
||||||
|
request = ln.ListChannelsRequest(
|
||||||
|
active_only=True,
|
||||||
|
inactive_only=False,
|
||||||
|
public_only=False,
|
||||||
|
private_only=False,
|
||||||
|
)
|
||||||
|
response = stub.ListChannels(request)
|
||||||
|
|
||||||
|
total_active_channels = len(response.channels)
|
||||||
|
for channel in response.channels:
|
||||||
|
# log.debug(channel)
|
||||||
|
total_remote_balance_sat += channel.remote_balance
|
||||||
|
|
||||||
|
except grpc.RpcError as err:
|
||||||
|
if err._state.__dict__['code'] == grpc.StatusCode.UNIMPLEMENTED:
|
||||||
|
log.debug("wallet is 'locked'")
|
||||||
|
else:
|
||||||
|
log.warning("an unknown RpcError occurred")
|
||||||
|
log.warning(err)
|
||||||
|
|
||||||
|
except Exception as err:
|
||||||
|
log.warning("an error occurred: {}".format(err))
|
||||||
|
|
||||||
|
return total_active_channels, total_remote_balance_sat
|
||||||
|
|
||||||
|
|
||||||
|
def check_invoice_paid(stub, invoice_r_hash, num_max_invoices=3):
|
||||||
|
# ToDo error handling
|
||||||
|
request = ln.ListInvoiceRequest(num_max_invoices=num_max_invoices, reversed=True)
|
||||||
|
response = stub.ListInvoices(request)
|
||||||
|
|
||||||
|
for invoice in response.invoices:
|
||||||
|
hex_str = convert_r_hash_hex_bytes(invoice.r_hash)
|
||||||
|
|
||||||
|
if hex_str == invoice_r_hash:
|
||||||
|
if invoice.settled:
|
||||||
|
log.debug("found - and settled: {}".format(invoice))
|
||||||
|
amt_paid_sat = invoice.amt_paid_sat
|
||||||
|
return True, amt_paid_sat
|
||||||
|
else:
|
||||||
|
log.debug("found - but NOT settled.")
|
||||||
|
return False, None
|
||||||
|
else:
|
||||||
|
log.warning("invoice NOT found")
|
||||||
|
return False, None
|
||||||
|
|
||||||
|
|
||||||
|
def create_invoice(stub, memo="", value=0):
|
||||||
|
# ToDo error handling
|
||||||
|
request = ln.Invoice(memo=memo, value=value)
|
||||||
|
response = stub.AddInvoice(request)
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
def get_node_uri(stub):
|
||||||
|
# ToDo error handling
|
||||||
|
response = stub.GetInfo(ln.GetInfoRequest())
|
||||||
|
if response.uris:
|
||||||
|
return response.uris[0]
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
network = "bitcoin"
|
||||||
|
chain = "main"
|
||||||
|
|
||||||
|
stub_readonly = ReadOnlyStub(network=network, chain=chain)
|
||||||
|
pid_ok, listen_ok, unlocked, synced_to_chain, synced_to_graph = check_lnd(stub_readonly)
|
||||||
|
print(pid_ok, listen_ok, unlocked, synced_to_chain, synced_to_graph)
|
||||||
|
|
||||||
|
if pid_ok and listen_ok and unlocked:
|
||||||
|
node_uri = get_node_uri(stub_readonly)
|
||||||
|
print("Node URI: {}".format(node_uri))
|
||||||
|
|
||||||
|
num, sats = check_lnd_channels(stub_readonly)
|
||||||
|
print("Total Channels: {}".format(num))
|
||||||
|
print("Total Remote Capacity: {}".format(sats))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
195
home.admin/BlitzTUI/blitztui/config.py
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
from configparser import ConfigParser, DEFAULTSECT
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class LndConfig(object):
|
||||||
|
def __init__(self, abs_path="/mnt/hdd/lnd/lnd.conf"):
|
||||||
|
self.abs_path = abs_path
|
||||||
|
|
||||||
|
# default values for LND Configuration
|
||||||
|
self.rpc_listen = ""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def rpc_listen_host(self):
|
||||||
|
return self.rpc_listen.split(":")[0]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def rpc_listen_port(self):
|
||||||
|
try:
|
||||||
|
return int(self.rpc_listen.split(":")[1])
|
||||||
|
except (IndexError, TypeError, ValueError):
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def reload(self):
|
||||||
|
"""load config from file"""
|
||||||
|
parser = ConfigParser()
|
||||||
|
|
||||||
|
log.debug("loading config from file: {}".format(self.abs_path))
|
||||||
|
with open(self.abs_path) as f:
|
||||||
|
parser.read_string(f.read())
|
||||||
|
|
||||||
|
app_options = parser["Application Options"]
|
||||||
|
|
||||||
|
self.rpc_listen = get_str_clean(app_options, "rpclisten", self.rpc_listen)
|
||||||
|
|
||||||
|
|
||||||
|
class RaspiBlitzConfig(object):
|
||||||
|
def __init__(self, abs_path="/mnt/hdd/raspiblitz.conf"):
|
||||||
|
self.abs_path = abs_path
|
||||||
|
|
||||||
|
# default values for RaspiBlitz Configuration
|
||||||
|
self.auto_nat_discovery = False
|
||||||
|
self.auto_pilot = False
|
||||||
|
self.auto_unlock = False
|
||||||
|
self.chain = ""
|
||||||
|
self.dynDomain = ""
|
||||||
|
self.dyn_update_url = ""
|
||||||
|
self.hostname = ""
|
||||||
|
self.invoice_allow_donations = False
|
||||||
|
self.invoice_default_amount = 402
|
||||||
|
self.lcd_rotate = False
|
||||||
|
self.lnd_address = ""
|
||||||
|
self.lnd_port = ""
|
||||||
|
self.network = ""
|
||||||
|
self.public_ip = ""
|
||||||
|
self.rtl_web_interface = False
|
||||||
|
self.run_behind_tor = False
|
||||||
|
self.ssh_tunnel = ""
|
||||||
|
self.touchscreen = False
|
||||||
|
self.version = ""
|
||||||
|
|
||||||
|
def reload(self):
|
||||||
|
"""load config from file"""
|
||||||
|
parser = ConfigParser()
|
||||||
|
|
||||||
|
log.debug("loading config from file: {}".format(self.abs_path))
|
||||||
|
with open(self.abs_path) as f:
|
||||||
|
parser.read_string("[{}]\n".format(DEFAULTSECT) + f.read())
|
||||||
|
|
||||||
|
default_s = parser[DEFAULTSECT]
|
||||||
|
|
||||||
|
self.auto_nat_discovery = default_s.getboolean("autoNatDiscovery", self.auto_nat_discovery)
|
||||||
|
self.auto_pilot = default_s.getboolean("autoPilot", self.auto_pilot)
|
||||||
|
self.auto_unlock = default_s.getboolean("autoUnlock", self.auto_unlock)
|
||||||
|
self.chain = get_str_clean(default_s, "chain", self.chain)
|
||||||
|
self.dynDomain = get_str_clean(default_s, "dynDomain", self.dynDomain)
|
||||||
|
self.dyn_update_url = get_str_clean(default_s, "dynUpdateUrl", self.dyn_update_url)
|
||||||
|
self.hostname = get_str_clean(default_s, "hostname", self.hostname)
|
||||||
|
self.invoice_allow_donations = default_s.getboolean("invoiceAllowDonations", self.invoice_allow_donations)
|
||||||
|
self.invoice_default_amount = get_int_safe(default_s, "invoiceDefaultAmount", self.invoice_default_amount)
|
||||||
|
self.lcd_rotate = default_s.getboolean("lcdrotate", self.lcd_rotate)
|
||||||
|
self.lnd_address = get_str_clean(default_s, "lndAddress", self.lnd_address)
|
||||||
|
self.lnd_port = get_str_clean(default_s, "lndPort", self.lnd_port)
|
||||||
|
self.network = get_str_clean(default_s, "network", self.network)
|
||||||
|
self.public_ip = get_str_clean(default_s, "publicIP", self.public_ip)
|
||||||
|
self.rtl_web_interface = default_s.getboolean("rtlWebinterface", self.rtl_web_interface)
|
||||||
|
self.run_behind_tor = default_s.getboolean("runBehindTor", self.run_behind_tor)
|
||||||
|
self.ssh_tunnel = get_str_clean(default_s, "sshtunnel", self.ssh_tunnel)
|
||||||
|
self.touchscreen = default_s.getboolean("touchscreen", self.touchscreen)
|
||||||
|
self.version = get_str_clean(default_s, "raspiBlitzVersion", self.version)
|
||||||
|
|
||||||
|
|
||||||
|
class RaspiBlitzInfo(object):
|
||||||
|
def __init__(self, abs_path="/home/admin/raspiblitz.info"):
|
||||||
|
self.abs_path = abs_path
|
||||||
|
|
||||||
|
# default values for RaspiBlitz Info
|
||||||
|
self.base_image = ""
|
||||||
|
self.chain = ""
|
||||||
|
self.message = ""
|
||||||
|
self.network = ""
|
||||||
|
self.setup_step = 0
|
||||||
|
self.state = ""
|
||||||
|
self.undervoltage_reports = 0
|
||||||
|
|
||||||
|
def reload(self):
|
||||||
|
"""load config from file"""
|
||||||
|
parser = ConfigParser()
|
||||||
|
|
||||||
|
log.debug("loading config from file: {}".format(self.abs_path))
|
||||||
|
with open(self.abs_path) as f:
|
||||||
|
parser.read_string("[{}]\n".format(DEFAULTSECT) + f.read())
|
||||||
|
|
||||||
|
default_s = parser[DEFAULTSECT]
|
||||||
|
|
||||||
|
self.base_image = get_str_clean(default_s, "baseimage", self.base_image)
|
||||||
|
self.chain = get_str_clean(default_s, "chain", self.chain)
|
||||||
|
self.message = get_str_clean(default_s, "message", self.message)
|
||||||
|
self.network = get_str_clean(default_s, "network", self.network)
|
||||||
|
self.setup_step = get_int_safe(default_s, "setupStep", self.setup_step)
|
||||||
|
self.state = get_str_clean(default_s, "state", self.state)
|
||||||
|
self.undervoltage_reports = get_int_safe(default_s, "undervoltageReports", self.undervoltage_reports)
|
||||||
|
|
||||||
|
|
||||||
|
def get_int_safe(cp_section, key, default_value):
|
||||||
|
"""take a ConfigParser section, get key that might be string encoded int and return int"""
|
||||||
|
try:
|
||||||
|
value = cp_section.getint(key, default_value)
|
||||||
|
except ValueError:
|
||||||
|
_value = cp_section.get(key)
|
||||||
|
value = int(_value.strip("'").strip('"')) # this will raise an Exception if int() fails!
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
def get_str_clean(cp_section, key, default_value):
|
||||||
|
"""take a ConfigParser section, get key and strip leading and trailing \' and \" chars"""
|
||||||
|
value = cp_section.get(key, default_value)
|
||||||
|
if not value:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
return value.lstrip('"').lstrip("'").rstrip('"').rstrip("'")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
lnd_cfg = LndConfig()
|
||||||
|
if os.path.exists(lnd_cfg.abs_path):
|
||||||
|
lnd_cfg.reload()
|
||||||
|
|
||||||
|
print("=======\n= LND =\n=======")
|
||||||
|
print("rpc_list: \t\t{}".format(lnd_cfg.rpc_listen))
|
||||||
|
print("rpc_list_host: \t\t{}".format(lnd_cfg.rpc_listen_host))
|
||||||
|
print("rpc_list_port: \t\t{}".format(lnd_cfg.rpc_listen_port))
|
||||||
|
print("")
|
||||||
|
|
||||||
|
rb_cfg = RaspiBlitzConfig()
|
||||||
|
if os.path.exists(rb_cfg.abs_path):
|
||||||
|
rb_cfg.reload()
|
||||||
|
|
||||||
|
print("====================\n= RaspiBlitzConfig =\n====================")
|
||||||
|
print("auto_nat_discovery: \t\t{}".format(rb_cfg.auto_nat_discovery))
|
||||||
|
print("auto_pilot: \t\t\t{}".format(rb_cfg.auto_pilot))
|
||||||
|
print("auto_unlock: \t\t\t{}".format(rb_cfg.auto_unlock))
|
||||||
|
print("chain: \t\t\t\t{}".format(rb_cfg.chain))
|
||||||
|
print("dynDomain: \t\t\t{}".format(rb_cfg.dynDomain))
|
||||||
|
print("dyn_update_url: \t\t{}".format(rb_cfg.dyn_update_url))
|
||||||
|
print("hostname: \t\t\t{}".format(rb_cfg.hostname))
|
||||||
|
print("invoice_allow_donations: \t{}".format(rb_cfg.invoice_allow_donations))
|
||||||
|
print("invoice_default_amount: \t{}".format(rb_cfg.invoice_default_amount))
|
||||||
|
print("lcd_rotate: \t\t\t{}".format(rb_cfg.lcd_rotate))
|
||||||
|
print("lnd_address: \t\t\t{}".format(rb_cfg.lnd_address))
|
||||||
|
print("lnd_port: \t\t\t{}".format(rb_cfg.lnd_port))
|
||||||
|
print("network: \t\t\t{}".format(rb_cfg.network))
|
||||||
|
print("public_ip: \t\t\t{}".format(rb_cfg.public_ip))
|
||||||
|
print("rtl_web_interface: \t\t{}".format(rb_cfg.rtl_web_interface))
|
||||||
|
print("run_behind_tor: \t\t{}".format(rb_cfg.run_behind_tor))
|
||||||
|
print("ssh_tunnel: \t\t\t{}".format(rb_cfg.ssh_tunnel))
|
||||||
|
print("touchscreen: \t\t\t{}".format(rb_cfg.touchscreen))
|
||||||
|
print("version: \t\t\t{}".format(rb_cfg.version))
|
||||||
|
print("")
|
||||||
|
|
||||||
|
rb_info = RaspiBlitzInfo()
|
||||||
|
if os.path.exists(rb_info.abs_path):
|
||||||
|
rb_info.reload()
|
||||||
|
|
||||||
|
print("==================\n= RaspiBlitzInfo =\n==================")
|
||||||
|
print("state: \t\t{}".format(rb_info.state))
|
||||||
|
print("")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
48
home.admin/BlitzTUI/blitztui/file_logger.py
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import json
|
||||||
|
import logging
|
||||||
|
import logging.config
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
IS_WIN32_ENV = sys.platform == "win32"
|
||||||
|
|
||||||
|
|
||||||
|
def setup_logging(default_path=os.path.abspath(os.path.expanduser('~/.blitz-tui.json'))):
|
||||||
|
"""Setup logging configuration"""
|
||||||
|
path = default_path
|
||||||
|
if os.path.exists(path):
|
||||||
|
with open(path, 'rt') as f:
|
||||||
|
config = json.load(f)
|
||||||
|
logging.config.dictConfig(config)
|
||||||
|
|
||||||
|
else: # if $default_path does not exist use the following default log setup
|
||||||
|
|
||||||
|
if IS_WIN32_ENV:
|
||||||
|
log_file = "blitz-tui.log"
|
||||||
|
else:
|
||||||
|
log_file = os.path.abspath(os.path.expanduser('~/blitz-tui.log'))
|
||||||
|
|
||||||
|
default_config_as_dict = dict(
|
||||||
|
version=1,
|
||||||
|
disable_existing_loggers=False,
|
||||||
|
formatters={'simple': {'format': '%(asctime)s - %(levelname)s - %(message)s'},
|
||||||
|
'extended': {
|
||||||
|
'format': '%(asctime)s - %(name)s - %(levelname)s - %(module)s:%(lineno)d - %(message)s'}},
|
||||||
|
handlers={'console': {'class': 'logging.StreamHandler',
|
||||||
|
'level': 'INFO',
|
||||||
|
'formatter': 'extended',
|
||||||
|
'stream': 'ext://sys.stdout'},
|
||||||
|
'file_handler': {'class': 'logging.handlers.RotatingFileHandler',
|
||||||
|
'level': 'DEBUG',
|
||||||
|
'formatter': 'extended',
|
||||||
|
'filename': log_file,
|
||||||
|
'maxBytes': 10485760,
|
||||||
|
'backupCount': 0,
|
||||||
|
'encoding': 'utf8'}},
|
||||||
|
loggers={'infoblitz': {'level': 'DEBUG',
|
||||||
|
'handlers': ['console', 'file_handler'],
|
||||||
|
'propagate': 'no'}},
|
||||||
|
root={'level': 'DEBUG', 'handlers': ['console', 'file_handler']}
|
||||||
|
)
|
||||||
|
|
||||||
|
logging.config.dictConfig(default_config_as_dict)
|
45
home.admin/BlitzTUI/blitztui/file_watcher.py
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from PyQt5.QtCore import QThread, pyqtSignal
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
if sys.platform == "win32":
|
||||||
|
log.info("skipping inotify on win32 as it is not supported")
|
||||||
|
else:
|
||||||
|
import inotify.adapters
|
||||||
|
import inotify.constants
|
||||||
|
|
||||||
|
|
||||||
|
class FileWatcherThread(QThread):
|
||||||
|
signal = pyqtSignal()
|
||||||
|
|
||||||
|
def __init__(self, dir_names, file_names, *args, **kwargs):
|
||||||
|
QThread.__init__(self, *args, **kwargs)
|
||||||
|
self.dir_names = dir_names
|
||||||
|
self.file_names = file_names
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
# run method gets called when we start the thread
|
||||||
|
if sys.platform == "win32":
|
||||||
|
log.info("skipping inotify on win32 as it is not supported")
|
||||||
|
return
|
||||||
|
|
||||||
|
log.info("starting config watcher")
|
||||||
|
i = inotify.adapters.Inotify()
|
||||||
|
|
||||||
|
mask = inotify.constants.IN_MODIFY | inotify.constants.IN_CLOSE_WRITE
|
||||||
|
|
||||||
|
for dir_name in self.dir_names:
|
||||||
|
i.add_watch(dir_name, mask=mask)
|
||||||
|
|
||||||
|
for event in i.event_gen(yield_nones=False):
|
||||||
|
_, type_names, path, filename = event
|
||||||
|
|
||||||
|
log.debug("PATH=[{}] FILENAME=[{}] EVENT_TYPES={}".format(
|
||||||
|
path, filename, type_names))
|
||||||
|
|
||||||
|
if path in self.dir_names and filename in self.file_names:
|
||||||
|
log.info("watched file was modified/touched")
|
||||||
|
self.signal.emit()
|
646
home.admin/BlitzTUI/blitztui/main.py
Normal file
@ -0,0 +1,646 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import itertools
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import signal
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
from argparse import RawTextHelpFormatter
|
||||||
|
from functools import lru_cache
|
||||||
|
from io import BytesIO
|
||||||
|
from threading import Event
|
||||||
|
|
||||||
|
import qrcode
|
||||||
|
from PyQt5.QtCore import Qt, QProcess, QThread, pyqtSignal, QCoreApplication, QTimer, QEventLoop
|
||||||
|
from PyQt5.QtGui import QPixmap
|
||||||
|
from PyQt5.QtWidgets import QMainWindow, QApplication, QDialog, QDialogButtonBox
|
||||||
|
from blitztui.client import ReadOnlyStub, InvoiceStub
|
||||||
|
from blitztui.client import check_lnd, check_lnd_channels
|
||||||
|
from blitztui.client import check_invoice_paid, create_invoice, get_node_uri
|
||||||
|
from blitztui.client import convert_r_hash_hex_bytes
|
||||||
|
from blitztui.config import LndConfig, RaspiBlitzConfig, RaspiBlitzInfo
|
||||||
|
from blitztui.file_watcher import FileWatcherThread
|
||||||
|
from blitztui.memo import adjective_noun_pair
|
||||||
|
from blitztui.version import __version__
|
||||||
|
from blitztui.ui.home import Ui_MainWindow
|
||||||
|
from blitztui.ui.invoice import Ui_DialogSelectInvoice
|
||||||
|
from blitztui.ui.off import Ui_DialogConfirmOff
|
||||||
|
from blitztui.ui.qcode import Ui_DialogShowQrCode
|
||||||
|
from pyqtspinner.spinner import WaitingSpinner
|
||||||
|
|
||||||
|
log = logging.getLogger()
|
||||||
|
|
||||||
|
IS_DEV_ENV = os.getenv('RASPIBLITZ_DEV', '0').lower() in ['1', 'true', 't', 'y', 'yes', 'on']
|
||||||
|
IS_WIN32_ENV = sys.platform == "win32"
|
||||||
|
|
||||||
|
SCREEN_HEIGHT = 318
|
||||||
|
|
||||||
|
LND_CONF = "/mnt/hdd/lnd/lnd.conf"
|
||||||
|
RB_CONF = "/mnt/hdd/raspiblitz.conf"
|
||||||
|
RB_INFO = "/home/admin/raspiblitz.info"
|
||||||
|
|
||||||
|
STATUS_INTERVAL_LND = 30
|
||||||
|
STATUS_INTERVAL_LND_CHANNELS = 120
|
||||||
|
INVOICE_CHECK_TIMEOUT = 1800
|
||||||
|
INVOICE_CHECK_INTERVAL = 2.0 # 1800*2.0s == 3600s == 1 Hour during which the invoice is monitored
|
||||||
|
|
||||||
|
SCREEN_NODE_URI = "Node URI"
|
||||||
|
SCREEN_INVOICE = "Invoice"
|
||||||
|
|
||||||
|
|
||||||
|
class AppWindow(QMainWindow):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(AppWindow, self).__init__(*args, **kwargs)
|
||||||
|
self.ui = Ui_MainWindow()
|
||||||
|
self.ui.setupUi(self)
|
||||||
|
|
||||||
|
# translations..?!
|
||||||
|
self._translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
if IS_WIN32_ENV:
|
||||||
|
log.info("using dummy config on win32")
|
||||||
|
lnd_cfg_abs_path = os.path.join(os.path.dirname(__file__), "..", "data", os.path.basename(LND_CONF))
|
||||||
|
rb_cfg_abs_path = os.path.join(os.path.dirname(__file__), "..", "data", os.path.basename(RB_CONF))
|
||||||
|
rb_info_abs_path = os.path.join(os.path.dirname(__file__), "..", "data", os.path.basename(RB_INFO))
|
||||||
|
else:
|
||||||
|
lnd_cfg_abs_path = LND_CONF
|
||||||
|
rb_cfg_abs_path = RB_CONF
|
||||||
|
rb_info_abs_path = RB_INFO
|
||||||
|
|
||||||
|
# read config and info files
|
||||||
|
if not os.path.exists(lnd_cfg_abs_path):
|
||||||
|
raise Exception("file does not exist: {}".format(lnd_cfg_abs_path))
|
||||||
|
|
||||||
|
if not os.path.exists(rb_cfg_abs_path):
|
||||||
|
raise Exception("file does not exist: {}".format(rb_cfg_abs_path))
|
||||||
|
|
||||||
|
if not os.path.exists(rb_info_abs_path):
|
||||||
|
raise Exception("file does not exist: {}".format(rb_info_abs_path))
|
||||||
|
|
||||||
|
self.lnd_cfg = LndConfig(lnd_cfg_abs_path)
|
||||||
|
self.lnd_cfg.reload()
|
||||||
|
|
||||||
|
self.rb_cfg = RaspiBlitzConfig(rb_cfg_abs_path)
|
||||||
|
self.rb_cfg.reload()
|
||||||
|
|
||||||
|
self.rb_info = RaspiBlitzInfo(rb_info_abs_path)
|
||||||
|
self.rb_info.reload()
|
||||||
|
|
||||||
|
# initialize attributes
|
||||||
|
self.invoice_to_check = None
|
||||||
|
self.invoice_to_check_flag = None
|
||||||
|
|
||||||
|
self.uptime = 0
|
||||||
|
|
||||||
|
self.status_lnd_due = 0
|
||||||
|
self.status_lnd_interval = STATUS_INTERVAL_LND
|
||||||
|
self.status_lnd_pid_ok = False
|
||||||
|
self.status_lnd_listen_ok = False
|
||||||
|
self.status_lnd_unlocked = False
|
||||||
|
self.status_lnd_synced_to_chain = False
|
||||||
|
self.status_lnd_synced_to_graph = False
|
||||||
|
|
||||||
|
self.status_lnd_channel_due = 0
|
||||||
|
self.status_lnd_channel_interval = STATUS_INTERVAL_LND_CHANNELS
|
||||||
|
self.status_lnd_channel_total_active = 0
|
||||||
|
self.status_lnd_channel_total_remote_balance = 0
|
||||||
|
|
||||||
|
# initial updates
|
||||||
|
self.update_uptime()
|
||||||
|
self.update_status_lnd()
|
||||||
|
self.update_status_lnd_channels()
|
||||||
|
|
||||||
|
# initial update of Main Window Title Bar
|
||||||
|
self.update_title_bar()
|
||||||
|
|
||||||
|
# Align Main Window Top Left
|
||||||
|
self.move(0, 0)
|
||||||
|
|
||||||
|
# set as maximized (unless on Windows dev host)
|
||||||
|
if IS_WIN32_ENV:
|
||||||
|
log.info("not maximizing window on win32")
|
||||||
|
else:
|
||||||
|
self.setWindowState(Qt.WindowMaximized)
|
||||||
|
|
||||||
|
# Bindings: buttons
|
||||||
|
self.ui.pushButton_1.clicked.connect(self.on_button_1_clicked)
|
||||||
|
self.ui.pushButton_2.clicked.connect(self.on_button_2_clicked)
|
||||||
|
self.ui.pushButton_3.clicked.connect(self.on_button_3_clicked)
|
||||||
|
self.ui.pushButton_4.clicked.connect(self.on_button_4_clicked)
|
||||||
|
|
||||||
|
# disable button 1 for now
|
||||||
|
self.ui.pushButton_1.setEnabled(False)
|
||||||
|
|
||||||
|
# connect error dismiss button and hide for start
|
||||||
|
self.ui.buttonBox_close.button(QDialogButtonBox.Close).setText("Ok")
|
||||||
|
self.ui.buttonBox_close.button(QDialogButtonBox.Close).clicked.connect(self.hide_error)
|
||||||
|
self.hide_error()
|
||||||
|
|
||||||
|
# Show QR Code Dialog Windows
|
||||||
|
self.w_qr_code = QDialog(flags=(Qt.Dialog | Qt.FramelessWindowHint))
|
||||||
|
self.ui_qr_code = Ui_DialogShowQrCode()
|
||||||
|
self.ui_qr_code.setupUi(self.w_qr_code)
|
||||||
|
self.w_qr_code.move(0, 0)
|
||||||
|
|
||||||
|
# SPINNER for CR Code Dialog Window
|
||||||
|
self.ui_qr_code.spinner = WaitingSpinner(self.w_qr_code)
|
||||||
|
|
||||||
|
self.beat_thread = BeatThread()
|
||||||
|
self.beat_thread.signal.connect(self.process_beat)
|
||||||
|
self.beat_thread.start()
|
||||||
|
|
||||||
|
self.generate_qr_code_thread = GenerateQrCodeThread()
|
||||||
|
self.generate_qr_code_thread.signal.connect(self.generate_qr_code_finished)
|
||||||
|
|
||||||
|
self.file_watcher = FileWatcherThread(
|
||||||
|
dir_names=[os.path.dirname(LND_CONF), os.path.dirname(RB_CONF), os.path.dirname(RB_INFO)],
|
||||||
|
file_names=[os.path.basename(LND_CONF), os.path.basename(RB_CONF), os.path.basename(RB_INFO)],
|
||||||
|
)
|
||||||
|
self.file_watcher.signal.connect(self.update_watched_attr)
|
||||||
|
self.file_watcher.start()
|
||||||
|
|
||||||
|
# finally start 00infoBlitz.sh in dedicated xterm frame
|
||||||
|
self.start_info_lcd()
|
||||||
|
|
||||||
|
self.show()
|
||||||
|
|
||||||
|
def start_info_lcd(self, pause=12):
|
||||||
|
# if system has been running for more than 90 seconds then skip pause
|
||||||
|
if self.uptime > 90:
|
||||||
|
pause = 0
|
||||||
|
|
||||||
|
process = QProcess(self)
|
||||||
|
process.setProcessChannelMode(QProcess.MergedChannels)
|
||||||
|
# connect the stdout_item to the Process StandardOutput
|
||||||
|
# it gets constantly update as the process emit std output
|
||||||
|
process.readyReadStandardOutput.connect(
|
||||||
|
lambda: log.info(str(process.readAllStandardOutput().data().decode('utf-8'))))
|
||||||
|
|
||||||
|
process.start('xterm', ['-fn', 'fixed', '-into', str(int(self.ui.widget.winId())),
|
||||||
|
'+sb', '-hold', '-e', 'bash -c \"/home/admin/00infoLCD.sh --pause {}\"'.format(pause)])
|
||||||
|
|
||||||
|
def check_invoice(self, flag, tick=0):
|
||||||
|
log.info("checking invoice paid (Tick: {})".format(tick))
|
||||||
|
self.invoice_to_check_flag = flag
|
||||||
|
|
||||||
|
if tick >= INVOICE_CHECK_TIMEOUT:
|
||||||
|
log.debug("canceled checking invoice paid")
|
||||||
|
flag.set()
|
||||||
|
|
||||||
|
if IS_DEV_ENV:
|
||||||
|
res = False
|
||||||
|
amt_paid_sat = 123123402
|
||||||
|
|
||||||
|
if tick == 5:
|
||||||
|
res = True
|
||||||
|
|
||||||
|
else:
|
||||||
|
stub_readonly = ReadOnlyStub(network=self.rb_cfg.network, chain=self.rb_cfg.chain)
|
||||||
|
res, amt_paid_sat = check_invoice_paid(stub_readonly, self.invoice_to_check)
|
||||||
|
log.debug("result of invoice check: {}".format(res))
|
||||||
|
|
||||||
|
if res:
|
||||||
|
log.debug("paid!")
|
||||||
|
self.ui_qr_code.qcode.setMargin(8)
|
||||||
|
self.ui_qr_code.qcode.setPixmap(QPixmap(":/RaspiBlitz/images/Paid_Stamp.png"))
|
||||||
|
|
||||||
|
if amt_paid_sat:
|
||||||
|
self.ui_qr_code.status_value.setText("Paid")
|
||||||
|
self.ui_qr_code.amt_paid_value.setText("{}".format(amt_paid_sat))
|
||||||
|
else:
|
||||||
|
self.ui_qr_code.status_value.setText("Paid")
|
||||||
|
|
||||||
|
flag.set()
|
||||||
|
|
||||||
|
def update_status_lnd(self):
|
||||||
|
if IS_WIN32_ENV:
|
||||||
|
return
|
||||||
|
|
||||||
|
# log.debug("update_status_lnd due: {}".format(self.status_lnd_due))
|
||||||
|
if self.status_lnd_due <= self.uptime:
|
||||||
|
log.debug("updating status_lnd")
|
||||||
|
stub_readonly = ReadOnlyStub(network=self.rb_cfg.network, chain=self.rb_cfg.chain)
|
||||||
|
pid_ok, listen_ok, unlocked, synced_to_chain, synced_to_graph = check_lnd(stub_readonly)
|
||||||
|
self.status_lnd_pid_ok = pid_ok
|
||||||
|
self.status_lnd_listen_ok = listen_ok
|
||||||
|
self.status_lnd_unlocked = unlocked
|
||||||
|
self.status_lnd_synced_to_chain = synced_to_chain
|
||||||
|
self.status_lnd_synced_to_graph = synced_to_graph
|
||||||
|
# set next due time
|
||||||
|
self.status_lnd_due = self.uptime + self.status_lnd_interval
|
||||||
|
|
||||||
|
def update_status_lnd_channels(self):
|
||||||
|
if IS_WIN32_ENV:
|
||||||
|
return
|
||||||
|
|
||||||
|
# log.debug("update_status_lnd_channel due: {}".format(self.status_lnd_channel_due))
|
||||||
|
if self.status_lnd_channel_due <= self.uptime:
|
||||||
|
log.debug("updating status_lnd_channels")
|
||||||
|
stub_readonly = ReadOnlyStub(network=self.rb_cfg.network, chain=self.rb_cfg.chain)
|
||||||
|
self.status_lnd_channel_total_active, self.status_lnd_channel_total_remote_balance = \
|
||||||
|
check_lnd_channels(stub_readonly)
|
||||||
|
# set next due time
|
||||||
|
self.status_lnd_channel_due = self.uptime + self.status_lnd_channel_interval
|
||||||
|
|
||||||
|
def update_title_bar(self):
|
||||||
|
log.debug("updating: Main Window Title Bar")
|
||||||
|
self.setWindowTitle(self._translate("MainWindow", "RaspiBlitz v{} - {} - {}net".format(self.rb_cfg.version,
|
||||||
|
self.rb_cfg.network,
|
||||||
|
self.rb_cfg.chain)))
|
||||||
|
|
||||||
|
def update_uptime(self):
|
||||||
|
if IS_WIN32_ENV:
|
||||||
|
self.uptime += 1
|
||||||
|
else:
|
||||||
|
with open('/proc/uptime', 'r') as f:
|
||||||
|
self.uptime = float(f.readline().split()[0])
|
||||||
|
# log.info("Uptime: {}".format(self.uptime))
|
||||||
|
|
||||||
|
def process_beat(self, _):
|
||||||
|
self.update_uptime()
|
||||||
|
self.update_status_lnd()
|
||||||
|
self.update_status_lnd_channels()
|
||||||
|
|
||||||
|
def update_watched_attr(self):
|
||||||
|
log.debug("updating: watched attributes")
|
||||||
|
self.lnd_cfg.reload()
|
||||||
|
self.rb_cfg.reload()
|
||||||
|
self.rb_info.reload()
|
||||||
|
|
||||||
|
# add anything here that should be updated now too
|
||||||
|
self.update_title_bar()
|
||||||
|
|
||||||
|
def hide_error(self):
|
||||||
|
self.ui.error_label.hide()
|
||||||
|
self.ui.buttonBox_close.hide()
|
||||||
|
|
||||||
|
def show_qr_code(self, data, screen=None, memo=None, status=None, inv_amt=None, amt_paid="N/A"):
|
||||||
|
log.debug("show_qr_code: {}".format(data))
|
||||||
|
# reset to logo and set text
|
||||||
|
self.ui_qr_code.qcode.setMargin(48)
|
||||||
|
self.ui_qr_code.qcode.setPixmap(QPixmap(":/RaspiBlitz/images/RaspiBlitz_Logo_Stacked.png"))
|
||||||
|
|
||||||
|
if screen == SCREEN_NODE_URI:
|
||||||
|
self.ui_qr_code.memo_key.show()
|
||||||
|
self.ui_qr_code.memo_key.setText("Node URI")
|
||||||
|
|
||||||
|
_tmp = data.split("@")
|
||||||
|
pub = _tmp[0]
|
||||||
|
_tmp2 = _tmp[1].split(":")
|
||||||
|
host = _tmp2[0]
|
||||||
|
port = _tmp2[1]
|
||||||
|
|
||||||
|
n = 16
|
||||||
|
pub = [(pub[i:i + n]) for i in range(0, len(pub), n)]
|
||||||
|
host = [(host[i:i + n]) for i in range(0, len(host), n)]
|
||||||
|
self.ui_qr_code.memo_value.show()
|
||||||
|
self.ui_qr_code.memo_value.setText("{} \n@\n{} \n:{}".format(" ".join(pub), " ".join(host), port))
|
||||||
|
|
||||||
|
self.ui_qr_code.status_key.hide()
|
||||||
|
self.ui_qr_code.status_value.hide()
|
||||||
|
self.ui_qr_code.inv_amt_key.hide()
|
||||||
|
self.ui_qr_code.inv_amt_value.hide()
|
||||||
|
self.ui_qr_code.amt_paid_key.hide()
|
||||||
|
self.ui_qr_code.amt_paid_value.hide()
|
||||||
|
|
||||||
|
if screen == SCREEN_INVOICE:
|
||||||
|
self.ui_qr_code.memo_key.show()
|
||||||
|
self.ui_qr_code.memo_key.setText("Invoice Memo")
|
||||||
|
|
||||||
|
self.ui_qr_code.memo_value.show()
|
||||||
|
self.ui_qr_code.memo_value.setText(memo)
|
||||||
|
|
||||||
|
self.ui_qr_code.status_key.show()
|
||||||
|
self.ui_qr_code.status_value.show()
|
||||||
|
self.ui_qr_code.status_value.setText(status)
|
||||||
|
|
||||||
|
self.ui_qr_code.inv_amt_key.show()
|
||||||
|
self.ui_qr_code.inv_amt_value.show()
|
||||||
|
self.ui_qr_code.inv_amt_value.setText("{}".format(inv_amt))
|
||||||
|
|
||||||
|
self.ui_qr_code.amt_paid_key.show()
|
||||||
|
self.ui_qr_code.amt_paid_value.show()
|
||||||
|
self.ui_qr_code.amt_paid_value.setText("{}".format(amt_paid))
|
||||||
|
|
||||||
|
# set function and start thread
|
||||||
|
self.generate_qr_code_thread.data = data
|
||||||
|
self.generate_qr_code_thread.start()
|
||||||
|
self.ui_qr_code.spinner.start()
|
||||||
|
|
||||||
|
self.w_qr_code.activateWindow()
|
||||||
|
self.w_qr_code.show()
|
||||||
|
|
||||||
|
rsp = self.w_qr_code.exec_()
|
||||||
|
if rsp == QDialog.Accepted:
|
||||||
|
log.info("QR: pressed OK - canceling invoice check")
|
||||||
|
if self.invoice_to_check_flag:
|
||||||
|
self.invoice_to_check_flag.set()
|
||||||
|
|
||||||
|
def generate_qr_code_finished(self, img):
|
||||||
|
buf = BytesIO()
|
||||||
|
img.save(buf, "PNG")
|
||||||
|
|
||||||
|
qt_pixmap = QPixmap()
|
||||||
|
qt_pixmap.loadFromData(buf.getvalue(), "PNG")
|
||||||
|
self.ui_qr_code.spinner.stop()
|
||||||
|
self.ui_qr_code.qcode.setMargin(2)
|
||||||
|
self.ui_qr_code.qcode.setPixmap(qt_pixmap)
|
||||||
|
|
||||||
|
def on_button_1_clicked(self):
|
||||||
|
log.debug("clicked: B1: {}".format(self.winId()))
|
||||||
|
# self.start_info_lcd(pause=0)
|
||||||
|
|
||||||
|
def on_button_2_clicked(self):
|
||||||
|
log.debug("clicked: B2: {}".format(self.winId()))
|
||||||
|
|
||||||
|
if not (self.status_lnd_pid_ok and self.status_lnd_listen_ok):
|
||||||
|
log.warning("LND is not ready")
|
||||||
|
self.ui.error_label.show()
|
||||||
|
self.ui.error_label.setText("Err: LND is not ready!")
|
||||||
|
self.ui.buttonBox_close.show()
|
||||||
|
return
|
||||||
|
|
||||||
|
if not self.status_lnd_unlocked:
|
||||||
|
log.warning("LND is locked")
|
||||||
|
self.ui.error_label.show()
|
||||||
|
self.ui.error_label.setText("Err: LND is locked")
|
||||||
|
self.ui.buttonBox_close.show()
|
||||||
|
return
|
||||||
|
|
||||||
|
data = self.get_node_uri()
|
||||||
|
if data:
|
||||||
|
self.show_qr_code(data, SCREEN_NODE_URI)
|
||||||
|
else:
|
||||||
|
log.warning("Node URI is none!")
|
||||||
|
# TODO(frennkie) inform user
|
||||||
|
|
||||||
|
def on_button_3_clicked(self):
|
||||||
|
log.debug("clicked: B3: {}".format(self.winId()))
|
||||||
|
|
||||||
|
if not (self.status_lnd_pid_ok and self.status_lnd_listen_ok):
|
||||||
|
log.warning("LND is not ready")
|
||||||
|
self.ui.error_label.show()
|
||||||
|
self.ui.error_label.setText("Err: LND is not ready!")
|
||||||
|
self.ui.buttonBox_close.show()
|
||||||
|
return
|
||||||
|
|
||||||
|
if not self.status_lnd_unlocked:
|
||||||
|
log.warning("LND is locked")
|
||||||
|
self.ui.error_label.show()
|
||||||
|
self.ui.error_label.setText("Err: LND is locked")
|
||||||
|
self.ui.buttonBox_close.show()
|
||||||
|
return
|
||||||
|
|
||||||
|
if not self.status_lnd_channel_total_active:
|
||||||
|
log.warning("not creating invoice: unable to receive - no open channels")
|
||||||
|
self.ui.error_label.show()
|
||||||
|
self.ui.error_label.setText("Err: No open channels!")
|
||||||
|
self.ui.buttonBox_close.show()
|
||||||
|
return
|
||||||
|
|
||||||
|
if not self.status_lnd_channel_total_remote_balance:
|
||||||
|
log.warning("not creating invoice: unable to receive - no remote capacity on any channel")
|
||||||
|
self.ui.error_label.show()
|
||||||
|
self.ui.error_label.setText("Err: No remote capacity!")
|
||||||
|
self.ui.buttonBox_close.show()
|
||||||
|
return
|
||||||
|
|
||||||
|
dialog_b1 = QDialog(flags=(Qt.Dialog | Qt.FramelessWindowHint))
|
||||||
|
ui = Ui_DialogSelectInvoice()
|
||||||
|
ui.setupUi(dialog_b1)
|
||||||
|
|
||||||
|
dialog_b1.move(0, 0)
|
||||||
|
|
||||||
|
ui.buttonBox.button(QDialogButtonBox.Yes).setText("{} SAT".format(self.rb_cfg.invoice_default_amount))
|
||||||
|
ui.buttonBox.button(QDialogButtonBox.Ok).setText("Donation")
|
||||||
|
if self.rb_cfg.invoice_allow_donations:
|
||||||
|
ui.buttonBox.button(QDialogButtonBox.Ok).setEnabled(True)
|
||||||
|
else:
|
||||||
|
ui.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False)
|
||||||
|
|
||||||
|
ui.buttonBox.button(QDialogButtonBox.Cancel).setText("Cancel")
|
||||||
|
|
||||||
|
ui.buttonBox.button(QDialogButtonBox.Yes).clicked.connect(self.b3_invoice_set_amt)
|
||||||
|
ui.buttonBox.button(QDialogButtonBox.Ok).clicked.connect(self.b3_invoice_custom_amt)
|
||||||
|
|
||||||
|
dialog_b1.show()
|
||||||
|
|
||||||
|
rsp = dialog_b1.exec_()
|
||||||
|
if not rsp == QDialog.Accepted:
|
||||||
|
log.info("B3: pressed is: Cancel")
|
||||||
|
|
||||||
|
def b3_invoice_set_amt(self):
|
||||||
|
log.info("b1 option: set amount")
|
||||||
|
|
||||||
|
check_invoice_thread = ClockStoppableThread(Event(), interval=INVOICE_CHECK_INTERVAL)
|
||||||
|
check_invoice_thread.signal.connect(self.check_invoice)
|
||||||
|
check_invoice_thread.start()
|
||||||
|
|
||||||
|
a, n = adjective_noun_pair()
|
||||||
|
inv_memo = "RB-{}-{}".format(a.capitalize(), n.capitalize())
|
||||||
|
|
||||||
|
new_invoice = self.create_new_invoice(inv_memo, amt=self.rb_cfg.invoice_default_amount)
|
||||||
|
data = new_invoice.payment_request
|
||||||
|
self.show_qr_code(data, SCREEN_INVOICE, memo=inv_memo, status="Open",
|
||||||
|
inv_amt=self.rb_cfg.invoice_default_amount)
|
||||||
|
|
||||||
|
def b3_invoice_custom_amt(self):
|
||||||
|
log.info("b1 option: custom amount")
|
||||||
|
|
||||||
|
check_invoice_thread = ClockStoppableThread(Event(), interval=INVOICE_CHECK_INTERVAL)
|
||||||
|
check_invoice_thread.signal.connect(self.check_invoice)
|
||||||
|
check_invoice_thread.start()
|
||||||
|
|
||||||
|
a, n = adjective_noun_pair()
|
||||||
|
inv_memo = "RB-{}-{}".format(a.capitalize(), n.capitalize())
|
||||||
|
|
||||||
|
new_invoice = self.create_new_invoice(inv_memo, amt=0)
|
||||||
|
data = new_invoice.payment_request
|
||||||
|
self.show_qr_code(data, SCREEN_INVOICE, memo=inv_memo, status="Open", inv_amt="Donation")
|
||||||
|
|
||||||
|
def on_button_4_clicked(self):
|
||||||
|
log.debug("clicked: B4: {}".format(self.winId()))
|
||||||
|
|
||||||
|
dialog_b4 = QDialog(flags=(Qt.Dialog | Qt.FramelessWindowHint))
|
||||||
|
ui = Ui_DialogConfirmOff()
|
||||||
|
ui.setupUi(dialog_b4)
|
||||||
|
|
||||||
|
dialog_b4.move(0, 0)
|
||||||
|
|
||||||
|
ui.buttonBox.button(QDialogButtonBox.Yes).setText("Shutdown")
|
||||||
|
ui.buttonBox.button(QDialogButtonBox.Retry).setText("Restart")
|
||||||
|
ui.buttonBox.button(QDialogButtonBox.Cancel).setText("Cancel")
|
||||||
|
|
||||||
|
ui.buttonBox.button(QDialogButtonBox.Yes).clicked.connect(self.b4_shutdown)
|
||||||
|
ui.buttonBox.button(QDialogButtonBox.Retry).clicked.connect(self.b4_restart)
|
||||||
|
|
||||||
|
dialog_b4.show()
|
||||||
|
rsp = dialog_b4.exec_()
|
||||||
|
|
||||||
|
if rsp == QDialog.Accepted:
|
||||||
|
log.info("B4: pressed is: Accepted - Shutdown or Restart")
|
||||||
|
else:
|
||||||
|
log.info("B4: pressed is: Cancel")
|
||||||
|
|
||||||
|
def b4_shutdown(self):
|
||||||
|
log.info("shutdown")
|
||||||
|
if IS_WIN32_ENV:
|
||||||
|
log.info("skipping on win32")
|
||||||
|
return
|
||||||
|
|
||||||
|
process = QProcess(self)
|
||||||
|
process.start('xterm', ['-fn', 'fixed', '-into', str(int(self.ui.widget.winId())),
|
||||||
|
'+sb', '-hold', '-e', 'bash -c \"sudo /home/admin/XXshutdown.sh\"'])
|
||||||
|
|
||||||
|
def b4_restart(self):
|
||||||
|
log.info("restart")
|
||||||
|
if IS_WIN32_ENV:
|
||||||
|
log.info("skipping on win32")
|
||||||
|
return
|
||||||
|
|
||||||
|
process = QProcess(self)
|
||||||
|
process.start('xterm', ['-fn', 'fixed', '-into', str(int(self.ui.widget.winId())),
|
||||||
|
'+sb', '-hold', '-e', 'bash -c \"sudo /home/admin/XXreboot.sh\"'])
|
||||||
|
|
||||||
|
def create_new_invoice(self, memo="Pay to RaspiBlitz", amt=0):
|
||||||
|
if IS_DEV_ENV:
|
||||||
|
# Fake an invoice for dev
|
||||||
|
class FakeAddInvoiceResponse(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.add_index = 145
|
||||||
|
self.payment_request = "lnbc47110n1pwmfqcdpp5k55n5erv60mg6u4c8s3qggnw3dsn267e80ypjxxp6gj593" \
|
||||||
|
"p3c25sdq9vehk7cqzpgprn0ytv6ukxc2vclgag38nmsmlyggmd4zand9qay2l3gc5at" \
|
||||||
|
"ecxjynydyzhvxsysam9d46y5lgezh2nkufvn23403t3tz3lyhd070dgq625xp0"
|
||||||
|
self.r_hash = b'\xf9\xe3(\xf5\x84\xdad\x88\xe4%\xa7\x1c\x95\xbe\x8baJ\x1c\xc1\xad*\xed\xc8' \
|
||||||
|
b'\x158\x13\xdf\xffF\x9c\x95\x84'
|
||||||
|
|
||||||
|
new_invoice = FakeAddInvoiceResponse()
|
||||||
|
|
||||||
|
else:
|
||||||
|
stub_invoice = InvoiceStub(network=self.rb_cfg.network, chain=self.rb_cfg.chain)
|
||||||
|
new_invoice = create_invoice(stub_invoice, memo, amt)
|
||||||
|
|
||||||
|
log.info("#{}: {}".format(new_invoice.add_index, new_invoice.payment_request))
|
||||||
|
|
||||||
|
invoice_r_hash_hex_str = convert_r_hash_hex_bytes(new_invoice.r_hash)
|
||||||
|
self.invoice_to_check = invoice_r_hash_hex_str
|
||||||
|
log.info("noting down for checking: {}".format(invoice_r_hash_hex_str))
|
||||||
|
|
||||||
|
return new_invoice
|
||||||
|
|
||||||
|
def get_node_uri(self):
|
||||||
|
if IS_DEV_ENV:
|
||||||
|
return "535f209faaea75427949e3e6c1fc9edafbf751f08706506bb873fdc93ffc2d4e2c@pqcjuc47eqcv6mk2.onion:9735"
|
||||||
|
|
||||||
|
stub_readonly = ReadOnlyStub(network=self.rb_cfg.network, chain=self.rb_cfg.chain)
|
||||||
|
|
||||||
|
res = get_node_uri(stub_readonly)
|
||||||
|
log.info("Node URI: : {}".format(res))
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
class ClockStoppableThread(QThread):
|
||||||
|
signal = pyqtSignal('PyQt_PyObject', 'PyQt_PyObject')
|
||||||
|
|
||||||
|
def __init__(self, event, interval=0.5, *args, **kwargs):
|
||||||
|
QThread.__init__(self, *args, **kwargs)
|
||||||
|
|
||||||
|
self.stopped = event
|
||||||
|
self.interval = interval
|
||||||
|
# atomic (?!) counter
|
||||||
|
self.ctr = itertools.count()
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
log.info("starting stoppable clock")
|
||||||
|
while not self.stopped.wait(self.interval):
|
||||||
|
self.signal.emit(self.stopped, next(self.ctr))
|
||||||
|
|
||||||
|
|
||||||
|
class GenerateQrCodeThread(QThread):
|
||||||
|
signal = pyqtSignal('PyQt_PyObject')
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
QThread.__init__(self)
|
||||||
|
self.data = None
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
# run method gets called when we start the thread
|
||||||
|
img = get_qr_img(self.data)
|
||||||
|
# done, now inform the main thread with the output
|
||||||
|
self.signal.emit(img)
|
||||||
|
|
||||||
|
|
||||||
|
class BeatThread(QThread):
|
||||||
|
signal = pyqtSignal('PyQt_PyObject')
|
||||||
|
|
||||||
|
def __init__(self, interval=5000, *args, **kwargs):
|
||||||
|
QThread.__init__(self, *args, **kwargs)
|
||||||
|
|
||||||
|
self.interval = interval
|
||||||
|
|
||||||
|
self.beat_timer = QTimer()
|
||||||
|
self.beat_timer.moveToThread(self)
|
||||||
|
self.beat_timer.timeout.connect(self.tick)
|
||||||
|
|
||||||
|
def tick(self):
|
||||||
|
# log.debug("beat")
|
||||||
|
self.signal.emit(0)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
log.info("starting beat")
|
||||||
|
self.beat_timer.start(self.interval)
|
||||||
|
loop = QEventLoop()
|
||||||
|
loop.exec_()
|
||||||
|
|
||||||
|
|
||||||
|
@lru_cache(maxsize=32)
|
||||||
|
def get_qr_img(data):
|
||||||
|
for i in range(6, 1, -1):
|
||||||
|
time.sleep(1.0)
|
||||||
|
qr_img = qrcode.make(data, box_size=i)
|
||||||
|
log.info("Box Size: {}, Image Size: {}".format(i, qr_img.size[0]))
|
||||||
|
if qr_img.size[0] <= SCREEN_HEIGHT:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
raise Exception("none found")
|
||||||
|
return qr_img
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# make sure CTRL+C works
|
||||||
|
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
||||||
|
|
||||||
|
description = """BlitzTUI - the Touch-User-Interface for the RaspiBlitz project
|
||||||
|
|
||||||
|
Keep on stacking SATs..! :-D"""
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description=description, formatter_class=RawTextHelpFormatter)
|
||||||
|
parser.add_argument("-V", "--version",
|
||||||
|
help="print version", action="version",
|
||||||
|
version=__version__)
|
||||||
|
#
|
||||||
|
# parser.add_argument("-g", "--game",
|
||||||
|
# help="game binary", type=str)
|
||||||
|
#
|
||||||
|
# parser.add_argument("-s", "--skip",
|
||||||
|
# help="skip", action="store_true")
|
||||||
|
|
||||||
|
# parse args
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
# initialize app
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
|
||||||
|
w = AppWindow()
|
||||||
|
w.show()
|
||||||
|
|
||||||
|
# run app
|
||||||
|
sys.exit(app.exec_())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
3974
home.admin/BlitzTUI/blitztui/memo.py
Normal file
0
home.admin/BlitzTUI/blitztui/ui/__init__.py
Normal file
417
home.admin/BlitzTUI/blitztui/ui/home.py
Normal file
@ -0,0 +1,417 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Form implementation generated from reading ui file 'designer/home.ui'
|
||||||
|
#
|
||||||
|
# Created by: PyQt5 UI code generator 5.11.3
|
||||||
|
#
|
||||||
|
# WARNING! All changes made in this file will be lost!
|
||||||
|
|
||||||
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
class Ui_MainWindow(object):
|
||||||
|
def setupUi(self, MainWindow):
|
||||||
|
MainWindow.setObjectName("MainWindow")
|
||||||
|
MainWindow.resize(480, 300)
|
||||||
|
MainWindow.setMinimumSize(QtCore.QSize(0, 0))
|
||||||
|
MainWindow.setAutoFillBackground(False)
|
||||||
|
MainWindow.setStyleSheet("background-color: black")
|
||||||
|
self.centralwidget = QtWidgets.QWidget(MainWindow)
|
||||||
|
self.centralwidget.setObjectName("centralwidget")
|
||||||
|
self.splitter = QtWidgets.QSplitter(self.centralwidget)
|
||||||
|
self.splitter.setGeometry(QtCore.QRect(6, 5, 80, 280))
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.splitter.sizePolicy().hasHeightForWidth())
|
||||||
|
self.splitter.setSizePolicy(sizePolicy)
|
||||||
|
self.splitter.setOrientation(QtCore.Qt.Vertical)
|
||||||
|
self.splitter.setObjectName("splitter")
|
||||||
|
self.pushButton_1 = QtWidgets.QPushButton(self.splitter)
|
||||||
|
palette = QtGui.QPalette()
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.WindowText, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 70))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Button, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Text, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.ButtonText, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 70))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Base, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 70))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Window, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.WindowText, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 70))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Button, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Text, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.ButtonText, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 70))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Base, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 70))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Window, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.WindowText, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 70))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Button, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Text, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.ButtonText, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 70))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Base, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 70))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Window, brush)
|
||||||
|
self.pushButton_1.setPalette(palette)
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setFamily("Arial")
|
||||||
|
font.setBold(True)
|
||||||
|
font.setWeight(75)
|
||||||
|
self.pushButton_1.setFont(font)
|
||||||
|
self.pushButton_1.setStyleSheet("background-color: rgb(0, 0, 70);\n"
|
||||||
|
"color: rgb(255, 255, 255)")
|
||||||
|
self.pushButton_1.setObjectName("pushButton_1")
|
||||||
|
self.pushButton_2 = QtWidgets.QPushButton(self.splitter)
|
||||||
|
palette = QtGui.QPalette()
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.WindowText, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 70))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Button, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Text, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.ButtonText, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 70))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Base, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 70))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Window, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.WindowText, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 70))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Button, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Text, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.ButtonText, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 70))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Base, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 70))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Window, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.WindowText, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 70))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Button, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Text, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.ButtonText, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 70))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Base, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 70))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Window, brush)
|
||||||
|
self.pushButton_2.setPalette(palette)
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setFamily("Arial")
|
||||||
|
font.setBold(True)
|
||||||
|
font.setWeight(75)
|
||||||
|
self.pushButton_2.setFont(font)
|
||||||
|
self.pushButton_2.setStyleSheet("background-color: rgb(0, 0, 70);\n"
|
||||||
|
"color: rgb(255, 255, 255)")
|
||||||
|
self.pushButton_2.setObjectName("pushButton_2")
|
||||||
|
self.pushButton_3 = QtWidgets.QPushButton(self.splitter)
|
||||||
|
palette = QtGui.QPalette()
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.WindowText, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 70))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Button, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Text, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.ButtonText, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 70))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Base, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 70))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Window, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.WindowText, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 70))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Button, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Text, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.ButtonText, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 70))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Base, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 70))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Window, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.WindowText, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 70))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Button, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Text, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.ButtonText, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 70))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Base, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 70))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Window, brush)
|
||||||
|
self.pushButton_3.setPalette(palette)
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setFamily("Arial")
|
||||||
|
font.setBold(True)
|
||||||
|
font.setUnderline(False)
|
||||||
|
font.setWeight(75)
|
||||||
|
self.pushButton_3.setFont(font)
|
||||||
|
self.pushButton_3.setStyleSheet("background-color: rgb(0, 0, 70);\n"
|
||||||
|
"color: rgb(255, 255, 255)")
|
||||||
|
self.pushButton_3.setObjectName("pushButton_3")
|
||||||
|
self.pushButton_4 = QtWidgets.QPushButton(self.splitter)
|
||||||
|
palette = QtGui.QPalette()
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.WindowText, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 70))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Button, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Text, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.ButtonText, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 70))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Base, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 70))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Window, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.WindowText, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 70))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Button, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Text, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.ButtonText, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 70))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Base, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 70))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Window, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.WindowText, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 70))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Button, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Text, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.ButtonText, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 70))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Base, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 70))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Window, brush)
|
||||||
|
self.pushButton_4.setPalette(palette)
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setFamily("Arial")
|
||||||
|
font.setBold(True)
|
||||||
|
font.setWeight(75)
|
||||||
|
self.pushButton_4.setFont(font)
|
||||||
|
self.pushButton_4.setStyleSheet("background-color: rgb(0, 0, 70);\n"
|
||||||
|
"color: rgb(255, 255, 255)")
|
||||||
|
self.pushButton_4.setObjectName("pushButton_4")
|
||||||
|
self.widget = QtWidgets.QWidget(self.centralwidget)
|
||||||
|
self.widget.setGeometry(QtCore.QRect(92, 5, 380, 270))
|
||||||
|
self.widget.setStyleSheet("background-color: darkblue")
|
||||||
|
self.widget.setObjectName("widget")
|
||||||
|
self.error_label = QtWidgets.QLabel(self.centralwidget)
|
||||||
|
self.error_label.setGeometry(QtCore.QRect(112, 252, 301, 44))
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.error_label.sizePolicy().hasHeightForWidth())
|
||||||
|
self.error_label.setSizePolicy(sizePolicy)
|
||||||
|
palette = QtGui.QPalette()
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 0, 127))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.WindowText, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Button, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 0, 127))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Text, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 0, 127))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.ButtonText, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Base, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Window, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 0, 127))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.WindowText, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Button, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 0, 127))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Text, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 0, 127))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.ButtonText, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Base, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Window, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 0, 127))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.WindowText, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Button, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 0, 127))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Text, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(255, 0, 127))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.ButtonText, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Base, brush)
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
|
||||||
|
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||||
|
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Window, brush)
|
||||||
|
self.error_label.setPalette(palette)
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setFamily("Arial")
|
||||||
|
font.setPointSize(12)
|
||||||
|
font.setBold(False)
|
||||||
|
font.setItalic(False)
|
||||||
|
font.setWeight(50)
|
||||||
|
self.error_label.setFont(font)
|
||||||
|
self.error_label.setStyleSheet("background-color: rgb(0, 0, 0);\n"
|
||||||
|
"font: 12pt \"Arial\";\n"
|
||||||
|
"color: rgb(255, 0, 127);")
|
||||||
|
self.error_label.setScaledContents(False)
|
||||||
|
self.error_label.setAlignment(QtCore.Qt.AlignCenter)
|
||||||
|
self.error_label.setWordWrap(False)
|
||||||
|
self.error_label.setObjectName("error_label")
|
||||||
|
self.buttonBox_close = QtWidgets.QDialogButtonBox(self.centralwidget)
|
||||||
|
self.buttonBox_close.setGeometry(QtCore.QRect(420, 260, 56, 32))
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.buttonBox_close.sizePolicy().hasHeightForWidth())
|
||||||
|
self.buttonBox_close.setSizePolicy(sizePolicy)
|
||||||
|
self.buttonBox_close.setMinimumSize(QtCore.QSize(0, 0))
|
||||||
|
self.buttonBox_close.setMaximumSize(QtCore.QSize(16777215, 16777215))
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setFamily("Arial")
|
||||||
|
font.setPointSize(14)
|
||||||
|
font.setBold(False)
|
||||||
|
font.setItalic(False)
|
||||||
|
font.setWeight(50)
|
||||||
|
self.buttonBox_close.setFont(font)
|
||||||
|
self.buttonBox_close.setStyleSheet("background-color: lightgrey;\n"
|
||||||
|
"font: 14pt \"Arial\";")
|
||||||
|
self.buttonBox_close.setOrientation(QtCore.Qt.Vertical)
|
||||||
|
self.buttonBox_close.setStandardButtons(QtWidgets.QDialogButtonBox.Close)
|
||||||
|
self.buttonBox_close.setObjectName("buttonBox_close")
|
||||||
|
MainWindow.setCentralWidget(self.centralwidget)
|
||||||
|
|
||||||
|
self.retranslateUi(MainWindow)
|
||||||
|
QtCore.QMetaObject.connectSlotsByName(MainWindow)
|
||||||
|
|
||||||
|
def retranslateUi(self, MainWindow):
|
||||||
|
_translate = QtCore.QCoreApplication.translate
|
||||||
|
MainWindow.setWindowTitle(_translate("MainWindow", "RaspiBlitz"))
|
||||||
|
self.pushButton_1.setText(_translate("MainWindow", "Info"))
|
||||||
|
self.pushButton_2.setText(_translate("MainWindow", "Node"))
|
||||||
|
self.pushButton_3.setText(_translate("MainWindow", "Invoice"))
|
||||||
|
self.pushButton_4.setText(_translate("MainWindow", "Off"))
|
||||||
|
self.error_label.setText(_translate("MainWindow", "Error Text\n"
|
||||||
|
"Foobar"))
|
||||||
|
|
||||||
|
from . import resources_rc
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import sys
|
||||||
|
app = QtWidgets.QApplication(sys.argv)
|
||||||
|
MainWindow = QtWidgets.QMainWindow()
|
||||||
|
ui = Ui_MainWindow()
|
||||||
|
ui.setupUi(MainWindow)
|
||||||
|
MainWindow.show()
|
||||||
|
sys.exit(app.exec_())
|
||||||
|
|
79
home.admin/BlitzTUI/blitztui/ui/invoice.py
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Form implementation generated from reading ui file 'designer/invoice.ui'
|
||||||
|
#
|
||||||
|
# Created by: PyQt5 UI code generator 5.11.3
|
||||||
|
#
|
||||||
|
# WARNING! All changes made in this file will be lost!
|
||||||
|
|
||||||
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
class Ui_DialogSelectInvoice(object):
|
||||||
|
def setupUi(self, DialogSelectInvoice):
|
||||||
|
DialogSelectInvoice.setObjectName("DialogSelectInvoice")
|
||||||
|
DialogSelectInvoice.resize(480, 320)
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(DialogSelectInvoice.sizePolicy().hasHeightForWidth())
|
||||||
|
DialogSelectInvoice.setSizePolicy(sizePolicy)
|
||||||
|
DialogSelectInvoice.setStyleSheet("")
|
||||||
|
self.buttonBox = QtWidgets.QDialogButtonBox(DialogSelectInvoice)
|
||||||
|
self.buttonBox.setGeometry(QtCore.QRect(102, 110, 320, 340))
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.buttonBox.sizePolicy().hasHeightForWidth())
|
||||||
|
self.buttonBox.setSizePolicy(sizePolicy)
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setFamily("Arial")
|
||||||
|
font.setPointSize(28)
|
||||||
|
font.setBold(False)
|
||||||
|
font.setItalic(False)
|
||||||
|
font.setWeight(50)
|
||||||
|
self.buttonBox.setFont(font)
|
||||||
|
self.buttonBox.setStyleSheet("background-color: lightgrey;\n"
|
||||||
|
"font: 28pt \"Arial\";")
|
||||||
|
self.buttonBox.setOrientation(QtCore.Qt.Vertical)
|
||||||
|
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok|QtWidgets.QDialogButtonBox.Yes)
|
||||||
|
self.buttonBox.setObjectName("buttonBox")
|
||||||
|
self.label = QtWidgets.QLabel(DialogSelectInvoice)
|
||||||
|
self.label.setGeometry(QtCore.QRect(102, 30, 320, 64))
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setFamily("Arial")
|
||||||
|
font.setPointSize(20)
|
||||||
|
font.setBold(False)
|
||||||
|
font.setItalic(False)
|
||||||
|
font.setWeight(50)
|
||||||
|
self.label.setFont(font)
|
||||||
|
self.label.setStyleSheet("")
|
||||||
|
self.label.setAlignment(QtCore.Qt.AlignHCenter|QtCore.Qt.AlignTop)
|
||||||
|
self.label.setObjectName("label")
|
||||||
|
self.label_2 = QtWidgets.QLabel(DialogSelectInvoice)
|
||||||
|
self.label_2.setGeometry(QtCore.QRect(0, 0, 47, 318))
|
||||||
|
self.label_2.setText("")
|
||||||
|
self.label_2.setPixmap(QtGui.QPixmap(":/RaspiBlitz/images/RaspiBlitz_Logo_Main_270.png"))
|
||||||
|
self.label_2.setScaledContents(True)
|
||||||
|
self.label_2.setObjectName("label_2")
|
||||||
|
|
||||||
|
self.retranslateUi(DialogSelectInvoice)
|
||||||
|
self.buttonBox.accepted.connect(DialogSelectInvoice.accept)
|
||||||
|
self.buttonBox.rejected.connect(DialogSelectInvoice.reject)
|
||||||
|
QtCore.QMetaObject.connectSlotsByName(DialogSelectInvoice)
|
||||||
|
|
||||||
|
def retranslateUi(self, DialogSelectInvoice):
|
||||||
|
_translate = QtCore.QCoreApplication.translate
|
||||||
|
DialogSelectInvoice.setWindowTitle(_translate("DialogSelectInvoice", "Dialog"))
|
||||||
|
self.label.setText(_translate("DialogSelectInvoice", "Select Invoice"))
|
||||||
|
|
||||||
|
from . import resources_rc
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import sys
|
||||||
|
app = QtWidgets.QApplication(sys.argv)
|
||||||
|
DialogSelectInvoice = QtWidgets.QDialog()
|
||||||
|
ui = Ui_DialogSelectInvoice()
|
||||||
|
ui.setupUi(DialogSelectInvoice)
|
||||||
|
DialogSelectInvoice.show()
|
||||||
|
sys.exit(app.exec_())
|
||||||
|
|
84
home.admin/BlitzTUI/blitztui/ui/off.py
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Form implementation generated from reading ui file 'designer/off.ui'
|
||||||
|
#
|
||||||
|
# Created by: PyQt5 UI code generator 5.11.3
|
||||||
|
#
|
||||||
|
# WARNING! All changes made in this file will be lost!
|
||||||
|
|
||||||
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
class Ui_DialogConfirmOff(object):
|
||||||
|
def setupUi(self, DialogConfirmOff):
|
||||||
|
DialogConfirmOff.setObjectName("DialogConfirmOff")
|
||||||
|
DialogConfirmOff.resize(480, 320)
|
||||||
|
DialogConfirmOff.setStyleSheet("background-color: rgb(255, 128, 128)")
|
||||||
|
self.label_2 = QtWidgets.QLabel(DialogConfirmOff)
|
||||||
|
self.label_2.setGeometry(QtCore.QRect(9, 9, 16, 16))
|
||||||
|
self.label_2.setMaximumSize(QtCore.QSize(110, 320))
|
||||||
|
self.label_2.setText("")
|
||||||
|
self.label_2.setPixmap(QtGui.QPixmap(":/RaspiBlitz/images/RaspiBlitz_Logo_Main_rotate.png"))
|
||||||
|
self.label_2.setScaledContents(True)
|
||||||
|
self.label_2.setIndent(-4)
|
||||||
|
self.label_2.setObjectName("label_2")
|
||||||
|
self.label_3 = QtWidgets.QLabel(DialogConfirmOff)
|
||||||
|
self.label_3.setGeometry(QtCore.QRect(0, 0, 47, 318))
|
||||||
|
self.label_3.setText("")
|
||||||
|
self.label_3.setPixmap(QtGui.QPixmap(":/RaspiBlitz/images/RaspiBlitz_Logo_Main_270.png"))
|
||||||
|
self.label_3.setScaledContents(True)
|
||||||
|
self.label_3.setObjectName("label_3")
|
||||||
|
self.label = QtWidgets.QLabel(DialogConfirmOff)
|
||||||
|
self.label.setGeometry(QtCore.QRect(102, 30, 320, 64))
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setFamily("Arial")
|
||||||
|
font.setPointSize(20)
|
||||||
|
font.setBold(False)
|
||||||
|
font.setItalic(False)
|
||||||
|
font.setWeight(50)
|
||||||
|
self.label.setFont(font)
|
||||||
|
self.label.setStyleSheet("")
|
||||||
|
self.label.setAlignment(QtCore.Qt.AlignHCenter|QtCore.Qt.AlignTop)
|
||||||
|
self.label.setObjectName("label")
|
||||||
|
self.buttonBox = QtWidgets.QDialogButtonBox(DialogConfirmOff)
|
||||||
|
self.buttonBox.setGeometry(QtCore.QRect(102, 110, 320, 340))
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.buttonBox.sizePolicy().hasHeightForWidth())
|
||||||
|
self.buttonBox.setSizePolicy(sizePolicy)
|
||||||
|
self.buttonBox.setMinimumSize(QtCore.QSize(0, 0))
|
||||||
|
self.buttonBox.setMaximumSize(QtCore.QSize(16777215, 16777215))
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setFamily("Arial")
|
||||||
|
font.setPointSize(28)
|
||||||
|
font.setBold(False)
|
||||||
|
font.setItalic(False)
|
||||||
|
font.setWeight(50)
|
||||||
|
self.buttonBox.setFont(font)
|
||||||
|
self.buttonBox.setStyleSheet("background-color: lightgrey;\n"
|
||||||
|
"font: 28pt \"Arial\";")
|
||||||
|
self.buttonBox.setOrientation(QtCore.Qt.Vertical)
|
||||||
|
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Retry|QtWidgets.QDialogButtonBox.Yes)
|
||||||
|
self.buttonBox.setObjectName("buttonBox")
|
||||||
|
|
||||||
|
self.retranslateUi(DialogConfirmOff)
|
||||||
|
self.buttonBox.rejected.connect(DialogConfirmOff.reject)
|
||||||
|
self.buttonBox.accepted.connect(DialogConfirmOff.accept)
|
||||||
|
QtCore.QMetaObject.connectSlotsByName(DialogConfirmOff)
|
||||||
|
|
||||||
|
def retranslateUi(self, DialogConfirmOff):
|
||||||
|
_translate = QtCore.QCoreApplication.translate
|
||||||
|
DialogConfirmOff.setWindowTitle(_translate("DialogConfirmOff", "Dialog"))
|
||||||
|
self.label.setText(_translate("DialogConfirmOff", "Shutdown RaspiBlitz?"))
|
||||||
|
|
||||||
|
from . import resources_rc
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import sys
|
||||||
|
app = QtWidgets.QApplication(sys.argv)
|
||||||
|
DialogConfirmOff = QtWidgets.QDialog()
|
||||||
|
ui = Ui_DialogConfirmOff()
|
||||||
|
ui.setupUi(DialogConfirmOff)
|
||||||
|
DialogConfirmOff.show()
|
||||||
|
sys.exit(app.exec_())
|
||||||
|
|
207
home.admin/BlitzTUI/blitztui/ui/qcode.py
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Form implementation generated from reading ui file 'designer/qcode.ui'
|
||||||
|
#
|
||||||
|
# Created by: PyQt5 UI code generator 5.11.3
|
||||||
|
#
|
||||||
|
# WARNING! All changes made in this file will be lost!
|
||||||
|
|
||||||
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
class Ui_DialogShowQrCode(object):
|
||||||
|
def setupUi(self, DialogShowQrCode):
|
||||||
|
DialogShowQrCode.setObjectName("DialogShowQrCode")
|
||||||
|
DialogShowQrCode.resize(480, 320)
|
||||||
|
self.buttonBox = QtWidgets.QDialogButtonBox(DialogShowQrCode)
|
||||||
|
self.buttonBox.setGeometry(QtCore.QRect(326, 268, 150, 50))
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.buttonBox.sizePolicy().hasHeightForWidth())
|
||||||
|
self.buttonBox.setSizePolicy(sizePolicy)
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setFamily("Arial")
|
||||||
|
font.setPointSize(24)
|
||||||
|
self.buttonBox.setFont(font)
|
||||||
|
self.buttonBox.setStyleSheet("background-color: lightgrey;\n"
|
||||||
|
"font: 24pt \"Arial\";")
|
||||||
|
self.buttonBox.setOrientation(QtCore.Qt.Vertical)
|
||||||
|
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Ok)
|
||||||
|
self.buttonBox.setObjectName("buttonBox")
|
||||||
|
self.top_right_logo = QtWidgets.QLabel(DialogShowQrCode)
|
||||||
|
self.top_right_logo.setGeometry(QtCore.QRect(430, 2, 40, 60))
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.top_right_logo.sizePolicy().hasHeightForWidth())
|
||||||
|
self.top_right_logo.setSizePolicy(sizePolicy)
|
||||||
|
self.top_right_logo.setText("")
|
||||||
|
self.top_right_logo.setPixmap(QtGui.QPixmap(":/RaspiBlitz/images/RaspiBlitz_Logo_Berry.png"))
|
||||||
|
self.top_right_logo.setScaledContents(True)
|
||||||
|
self.top_right_logo.setAlignment(QtCore.Qt.AlignCenter)
|
||||||
|
self.top_right_logo.setObjectName("top_right_logo")
|
||||||
|
self.frame = QtWidgets.QFrame(DialogShowQrCode)
|
||||||
|
self.frame.setGeometry(QtCore.QRect(0, 0, 320, 320))
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.frame.sizePolicy().hasHeightForWidth())
|
||||||
|
self.frame.setSizePolicy(sizePolicy)
|
||||||
|
self.frame.setStyleSheet("background-color: rgb(255, 255, 255);")
|
||||||
|
self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
|
||||||
|
self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
|
||||||
|
self.frame.setObjectName("frame")
|
||||||
|
self.qcode = QtWidgets.QLabel(self.frame)
|
||||||
|
self.qcode.setGeometry(QtCore.QRect(1, 1, 318, 318))
|
||||||
|
self.qcode.setStyleSheet("background-color: white")
|
||||||
|
self.qcode.setText("")
|
||||||
|
self.qcode.setPixmap(QtGui.QPixmap(":/RaspiBlitz/images/RaspiBlitz_Logo_Stacked.png"))
|
||||||
|
self.qcode.setScaledContents(True)
|
||||||
|
self.qcode.setAlignment(QtCore.Qt.AlignCenter)
|
||||||
|
self.qcode.setObjectName("qcode")
|
||||||
|
self.label = QtWidgets.QLabel(DialogShowQrCode)
|
||||||
|
self.label.setGeometry(QtCore.QRect(330, 4, 88, 60))
|
||||||
|
self.label.setText("")
|
||||||
|
self.label.setPixmap(QtGui.QPixmap(":/RaspiBlitz/images/RaspiBlitz_Logo_Stacked.png"))
|
||||||
|
self.label.setScaledContents(True)
|
||||||
|
self.label.setAlignment(QtCore.Qt.AlignCenter)
|
||||||
|
self.label.setObjectName("label")
|
||||||
|
self.horizontalLayoutWidget = QtWidgets.QWidget(DialogShowQrCode)
|
||||||
|
self.horizontalLayoutWidget.setGeometry(QtCore.QRect(320, 70, 161, 191))
|
||||||
|
self.horizontalLayoutWidget.setObjectName("horizontalLayoutWidget")
|
||||||
|
self.verticalLayout = QtWidgets.QVBoxLayout(self.horizontalLayoutWidget)
|
||||||
|
self.verticalLayout.setContentsMargins(6, 0, 6, 0)
|
||||||
|
self.verticalLayout.setObjectName("verticalLayout")
|
||||||
|
self.line = QtWidgets.QFrame(self.horizontalLayoutWidget)
|
||||||
|
self.line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||||
|
self.line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||||
|
self.line.setObjectName("line")
|
||||||
|
self.verticalLayout.addWidget(self.line)
|
||||||
|
self.memo_key = QtWidgets.QLabel(self.horizontalLayoutWidget)
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setFamily("Arial")
|
||||||
|
font.setPointSize(11)
|
||||||
|
font.setBold(True)
|
||||||
|
font.setItalic(False)
|
||||||
|
font.setUnderline(False)
|
||||||
|
font.setWeight(75)
|
||||||
|
self.memo_key.setFont(font)
|
||||||
|
self.memo_key.setScaledContents(False)
|
||||||
|
self.memo_key.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop)
|
||||||
|
self.memo_key.setWordWrap(True)
|
||||||
|
self.memo_key.setObjectName("memo_key")
|
||||||
|
self.verticalLayout.addWidget(self.memo_key)
|
||||||
|
self.memo_value = QtWidgets.QLabel(self.horizontalLayoutWidget)
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setFamily("Arial")
|
||||||
|
font.setPointSize(11)
|
||||||
|
self.memo_value.setFont(font)
|
||||||
|
self.memo_value.setScaledContents(False)
|
||||||
|
self.memo_value.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTop|QtCore.Qt.AlignTrailing)
|
||||||
|
self.memo_value.setWordWrap(True)
|
||||||
|
self.memo_value.setObjectName("memo_value")
|
||||||
|
self.verticalLayout.addWidget(self.memo_value)
|
||||||
|
self.horizontalLayout = QtWidgets.QHBoxLayout()
|
||||||
|
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||||
|
self.status_key = QtWidgets.QLabel(self.horizontalLayoutWidget)
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setFamily("Arial")
|
||||||
|
font.setPointSize(11)
|
||||||
|
font.setBold(True)
|
||||||
|
font.setUnderline(False)
|
||||||
|
font.setWeight(75)
|
||||||
|
self.status_key.setFont(font)
|
||||||
|
self.status_key.setScaledContents(False)
|
||||||
|
self.status_key.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop)
|
||||||
|
self.status_key.setWordWrap(True)
|
||||||
|
self.status_key.setObjectName("status_key")
|
||||||
|
self.horizontalLayout.addWidget(self.status_key)
|
||||||
|
self.status_value = QtWidgets.QLabel(self.horizontalLayoutWidget)
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setFamily("Arial")
|
||||||
|
font.setPointSize(11)
|
||||||
|
self.status_value.setFont(font)
|
||||||
|
self.status_value.setScaledContents(False)
|
||||||
|
self.status_value.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTop|QtCore.Qt.AlignTrailing)
|
||||||
|
self.status_value.setWordWrap(True)
|
||||||
|
self.status_value.setObjectName("status_value")
|
||||||
|
self.horizontalLayout.addWidget(self.status_value)
|
||||||
|
self.verticalLayout.addLayout(self.horizontalLayout)
|
||||||
|
self.inv_amt_key = QtWidgets.QLabel(self.horizontalLayoutWidget)
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setFamily("Arial")
|
||||||
|
font.setPointSize(11)
|
||||||
|
font.setBold(True)
|
||||||
|
font.setWeight(75)
|
||||||
|
self.inv_amt_key.setFont(font)
|
||||||
|
self.inv_amt_key.setObjectName("inv_amt_key")
|
||||||
|
self.verticalLayout.addWidget(self.inv_amt_key)
|
||||||
|
self.inv_amt_value = QtWidgets.QLabel(self.horizontalLayoutWidget)
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setFamily("Arial")
|
||||||
|
font.setPointSize(11)
|
||||||
|
font.setBold(False)
|
||||||
|
font.setWeight(50)
|
||||||
|
self.inv_amt_value.setFont(font)
|
||||||
|
self.inv_amt_value.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
|
||||||
|
self.inv_amt_value.setObjectName("inv_amt_value")
|
||||||
|
self.verticalLayout.addWidget(self.inv_amt_value)
|
||||||
|
self.amt_paid_key = QtWidgets.QLabel(self.horizontalLayoutWidget)
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setFamily("Arial")
|
||||||
|
font.setPointSize(11)
|
||||||
|
font.setBold(True)
|
||||||
|
font.setWeight(75)
|
||||||
|
self.amt_paid_key.setFont(font)
|
||||||
|
self.amt_paid_key.setObjectName("amt_paid_key")
|
||||||
|
self.verticalLayout.addWidget(self.amt_paid_key)
|
||||||
|
self.amt_paid_value = QtWidgets.QLabel(self.horizontalLayoutWidget)
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setFamily("Arial")
|
||||||
|
font.setPointSize(11)
|
||||||
|
self.amt_paid_value.setFont(font)
|
||||||
|
self.amt_paid_value.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
|
||||||
|
self.amt_paid_value.setObjectName("amt_paid_value")
|
||||||
|
self.verticalLayout.addWidget(self.amt_paid_value)
|
||||||
|
self.spinner = QtWidgets.QWidget(DialogShowQrCode)
|
||||||
|
self.spinner.setGeometry(QtCore.QRect(440, 0, 40, 40))
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.spinner.sizePolicy().hasHeightForWidth())
|
||||||
|
self.spinner.setSizePolicy(sizePolicy)
|
||||||
|
self.spinner.setObjectName("spinner")
|
||||||
|
self.spinner.raise_()
|
||||||
|
self.buttonBox.raise_()
|
||||||
|
self.top_right_logo.raise_()
|
||||||
|
self.frame.raise_()
|
||||||
|
self.label.raise_()
|
||||||
|
self.horizontalLayoutWidget.raise_()
|
||||||
|
|
||||||
|
self.retranslateUi(DialogShowQrCode)
|
||||||
|
self.buttonBox.accepted.connect(DialogShowQrCode.accept)
|
||||||
|
QtCore.QMetaObject.connectSlotsByName(DialogShowQrCode)
|
||||||
|
|
||||||
|
def retranslateUi(self, DialogShowQrCode):
|
||||||
|
_translate = QtCore.QCoreApplication.translate
|
||||||
|
DialogShowQrCode.setWindowTitle(_translate("DialogShowQrCode", "Dialog"))
|
||||||
|
self.memo_key.setText(_translate("DialogShowQrCode", "Memo"))
|
||||||
|
self.memo_value.setText(_translate("DialogShowQrCode", "RB-Vivid-Badger"))
|
||||||
|
self.status_key.setText(_translate("DialogShowQrCode", "Status"))
|
||||||
|
self.status_value.setText(_translate("DialogShowQrCode", "Open/Paid"))
|
||||||
|
self.inv_amt_key.setText(_translate("DialogShowQrCode", "Invoice Amount"))
|
||||||
|
self.inv_amt_value.setText(_translate("DialogShowQrCode", "123456798"))
|
||||||
|
self.amt_paid_key.setText(_translate("DialogShowQrCode", "Amount Paid"))
|
||||||
|
self.amt_paid_value.setText(_translate("DialogShowQrCode", "N/A"))
|
||||||
|
|
||||||
|
from . import resources_rc
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import sys
|
||||||
|
app = QtWidgets.QApplication(sys.argv)
|
||||||
|
DialogShowQrCode = QtWidgets.QDialog()
|
||||||
|
ui = Ui_DialogShowQrCode()
|
||||||
|
ui.setupUi(DialogShowQrCode)
|
||||||
|
DialogShowQrCode.show()
|
||||||
|
sys.exit(app.exec_())
|
||||||
|
|
27597
home.admin/BlitzTUI/blitztui/ui/resources_rc.py
Normal file
8
home.admin/BlitzTUI/blitztui/version.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
""" Store the version here so:
|
||||||
|
# 1) we don't load dependencies by storing it in __init__.py
|
||||||
|
# 2) we can import it in setup.py for the same reason
|
||||||
|
# 3) we can import it into your module module
|
||||||
|
"""
|
||||||
|
|
||||||
|
__version_info__ = ('0', '41', '0')
|
||||||
|
__version__ = '.'.join(__version_info__)
|
2876
home.admin/BlitzTUI/data/Wordlist-Nouns-Common-Audited-Len-3-6.txt
Normal file
3
home.admin/BlitzTUI/data/lnd.conf
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# lnd configuration
|
||||||
|
[Application Options]
|
||||||
|
rpclisten=0.0.0.0:10009
|
19
home.admin/BlitzTUI/data/raspiblitz.conf
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# RASPIBLITZ CONFIG FILE
|
||||||
|
autoNatDiscovery=off
|
||||||
|
autoPilot=off
|
||||||
|
autoUnlock=on
|
||||||
|
chain=test
|
||||||
|
dynDomain=''
|
||||||
|
dynUpdateUrl=''
|
||||||
|
hostname=raspiblitz
|
||||||
|
invoiceAllowDonations=off
|
||||||
|
invoiceDefaultAmount=402
|
||||||
|
lcdrotate=1
|
||||||
|
lndAddress=''
|
||||||
|
lndPort='9735'
|
||||||
|
network=bitcoin
|
||||||
|
publicIP='1.2.3.4'
|
||||||
|
raspiBlitzVersion='1.3'
|
||||||
|
rtlWebinterface=off
|
||||||
|
runBehindTor=off
|
||||||
|
touchscreen=1
|
7
home.admin/BlitzTUI/data/raspiblitz.info
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
state=stresstest
|
||||||
|
message='Testing Hardware 60s'
|
||||||
|
network=bitcoin
|
||||||
|
chain=main
|
||||||
|
setupStep=100
|
||||||
|
baseimage=raspbian
|
||||||
|
undervoltageReports=0
|
1082
home.admin/BlitzTUI/designer/home.ui
Normal file
146
home.admin/BlitzTUI/designer/invoice.ui
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>DialogSelectInvoice</class>
|
||||||
|
<widget class="QDialog" name="DialogSelectInvoice">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>480</width>
|
||||||
|
<height>320</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Dialog</string>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>102</x>
|
||||||
|
<y>110</y>
|
||||||
|
<width>320</width>
|
||||||
|
<height>340</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Arial</family>
|
||||||
|
<pointsize>28</pointsize>
|
||||||
|
<weight>50</weight>
|
||||||
|
<italic>false</italic>
|
||||||
|
<bold>false</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">background-color: lightgrey;
|
||||||
|
font: 28pt "Arial";</string>
|
||||||
|
</property>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Yes</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>102</x>
|
||||||
|
<y>30</y>
|
||||||
|
<width>320</width>
|
||||||
|
<height>64</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Arial</family>
|
||||||
|
<pointsize>20</pointsize>
|
||||||
|
<weight>50</weight>
|
||||||
|
<italic>false</italic>
|
||||||
|
<bold>false</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Select Invoice</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignHCenter|Qt::AlignTop</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>47</width>
|
||||||
|
<height>318</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="pixmap">
|
||||||
|
<pixmap resource="../resources.qrc">:/RaspiBlitz/images/RaspiBlitz_Logo_Main_270.png</pixmap>
|
||||||
|
</property>
|
||||||
|
<property name="scaledContents">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
<resources>
|
||||||
|
<include location="../resources.qrc"/>
|
||||||
|
<include location="../resources.qrc"/>
|
||||||
|
</resources>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>DialogSelectInvoice</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>DialogSelectInvoice</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>
|
180
home.admin/BlitzTUI/designer/off.ui
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>DialogConfirmOff</class>
|
||||||
|
<widget class="QDialog" name="DialogConfirmOff">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>480</width>
|
||||||
|
<height>320</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Dialog</string>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">background-color: rgb(255, 128, 128)</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>9</x>
|
||||||
|
<y>9</y>
|
||||||
|
<width>16</width>
|
||||||
|
<height>16</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>110</width>
|
||||||
|
<height>320</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="pixmap">
|
||||||
|
<pixmap>:/RaspiBlitz/images/RaspiBlitz_Logo_Main_rotate.png</pixmap>
|
||||||
|
</property>
|
||||||
|
<property name="scaledContents">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="indent">
|
||||||
|
<number>-4</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>47</width>
|
||||||
|
<height>318</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="pixmap">
|
||||||
|
<pixmap resource="../resources.qrc">:/RaspiBlitz/images/RaspiBlitz_Logo_Main_270.png</pixmap>
|
||||||
|
</property>
|
||||||
|
<property name="scaledContents">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>102</x>
|
||||||
|
<y>30</y>
|
||||||
|
<width>320</width>
|
||||||
|
<height>64</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Arial</family>
|
||||||
|
<pointsize>20</pointsize>
|
||||||
|
<weight>50</weight>
|
||||||
|
<italic>false</italic>
|
||||||
|
<bold>false</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Shutdown RaspiBlitz?</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignHCenter|Qt::AlignTop</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>102</x>
|
||||||
|
<y>110</y>
|
||||||
|
<width>320</width>
|
||||||
|
<height>340</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>16777215</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Arial</family>
|
||||||
|
<pointsize>28</pointsize>
|
||||||
|
<weight>50</weight>
|
||||||
|
<italic>false</italic>
|
||||||
|
<bold>false</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">background-color: lightgrey;
|
||||||
|
font: 28pt "Arial";</string>
|
||||||
|
</property>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Retry|QDialogButtonBox::Yes</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
<resources>
|
||||||
|
<include location="../resources.qrc"/>
|
||||||
|
<include location="../resources.qrc"/>
|
||||||
|
</resources>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>DialogConfirmOff</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>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>DialogConfirmOff</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>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
384
home.admin/BlitzTUI/designer/qcode.ui
Normal file
@ -0,0 +1,384 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>DialogShowQrCode</class>
|
||||||
|
<widget class="QDialog" name="DialogShowQrCode">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>480</width>
|
||||||
|
<height>320</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Dialog</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>326</x>
|
||||||
|
<y>268</y>
|
||||||
|
<width>150</width>
|
||||||
|
<height>50</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Arial</family>
|
||||||
|
<pointsize>24</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">background-color: lightgrey;
|
||||||
|
font: 24pt "Arial";</string>
|
||||||
|
</property>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="top_right_logo">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>430</x>
|
||||||
|
<y>2</y>
|
||||||
|
<width>40</width>
|
||||||
|
<height>60</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="pixmap">
|
||||||
|
<pixmap resource="../resources.qrc">:/RaspiBlitz/images/RaspiBlitz_Logo_Berry.png</pixmap>
|
||||||
|
</property>
|
||||||
|
<property name="scaledContents">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QFrame" name="frame">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>320</width>
|
||||||
|
<height>320</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">background-color: rgb(255, 255, 255);</string>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
<widget class="QLabel" name="qcode">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>1</x>
|
||||||
|
<y>1</y>
|
||||||
|
<width>318</width>
|
||||||
|
<height>318</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">background-color: white</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="pixmap">
|
||||||
|
<pixmap resource="../resources.qrc">:/RaspiBlitz/images/RaspiBlitz_Logo_Stacked.png</pixmap>
|
||||||
|
</property>
|
||||||
|
<property name="scaledContents">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
<property name="margin">
|
||||||
|
<number>16</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>330</x>
|
||||||
|
<y>4</y>
|
||||||
|
<width>88</width>
|
||||||
|
<height>60</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="pixmap">
|
||||||
|
<pixmap resource="../resources.qrc">:/RaspiBlitz/images/RaspiBlitz_Logo_Stacked.png</pixmap>
|
||||||
|
</property>
|
||||||
|
<property name="scaledContents">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="horizontalLayoutWidget">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>320</x>
|
||||||
|
<y>70</y>
|
||||||
|
<width>161</width>
|
||||||
|
<height>191</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>6</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>6</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="line">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="memo_key">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Arial</family>
|
||||||
|
<pointsize>11</pointsize>
|
||||||
|
<weight>75</weight>
|
||||||
|
<italic>false</italic>
|
||||||
|
<bold>true</bold>
|
||||||
|
<underline>false</underline>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Memo</string>
|
||||||
|
</property>
|
||||||
|
<property name="scaledContents">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="memo_value">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Arial</family>
|
||||||
|
<pointsize>11</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>RB-Vivid-Badger</string>
|
||||||
|
</property>
|
||||||
|
<property name="scaledContents">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTop|Qt::AlignTrailing</set>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="status_key">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Arial</family>
|
||||||
|
<pointsize>11</pointsize>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
<underline>false</underline>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Status</string>
|
||||||
|
</property>
|
||||||
|
<property name="scaledContents">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="status_value">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Arial</family>
|
||||||
|
<pointsize>11</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Open/Paid</string>
|
||||||
|
</property>
|
||||||
|
<property name="scaledContents">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTop|Qt::AlignTrailing</set>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="inv_amt_key">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Arial</family>
|
||||||
|
<pointsize>11</pointsize>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Invoice Amount</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="inv_amt_value">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Arial</family>
|
||||||
|
<pointsize>11</pointsize>
|
||||||
|
<weight>50</weight>
|
||||||
|
<bold>false</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>123456798</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="amt_paid_key">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Arial</family>
|
||||||
|
<pointsize>11</pointsize>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Amount Paid</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="amt_paid_value">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Arial</family>
|
||||||
|
<pointsize>11</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>N/A</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="spinner" native="true">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>440</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>40</width>
|
||||||
|
<height>40</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<zorder>spinner</zorder>
|
||||||
|
<zorder>buttonBox</zorder>
|
||||||
|
<zorder>top_right_logo</zorder>
|
||||||
|
<zorder>frame</zorder>
|
||||||
|
<zorder>label</zorder>
|
||||||
|
<zorder>horizontalLayoutWidget</zorder>
|
||||||
|
</widget>
|
||||||
|
<resources>
|
||||||
|
<include location="../resources.qrc"/>
|
||||||
|
<include location="../resources.qrc"/>
|
||||||
|
</resources>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>DialogShowQrCode</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>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
166
home.admin/BlitzTUI/docs/README.md
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
# BlitzTUI Documentation (mainly for developers)
|
||||||
|
|
||||||
|
BlitzTUI is a part of the RaspiBlitz project and implements a Touch User Interface in PyQt5.
|
||||||
|
|
||||||
|
Make sure that PyQt5 is installed on the system
|
||||||
|
|
||||||
|
```
|
||||||
|
apt-get install python3-pyqt5
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Required tools
|
||||||
|
|
||||||
|
### for UI development
|
||||||
|
|
||||||
|
* QT Designer (GUI application for Linux, Mac and Windows)
|
||||||
|
|
||||||
|
### for compiling the .ui and .qrc files to python3
|
||||||
|
|
||||||
|
* pyuic5
|
||||||
|
* pyrcc5
|
||||||
|
|
||||||
|
`sudo apt-get install pyqt5-dev-tools`
|
||||||
|
|
||||||
|
### for building and uploading PyPI packages
|
||||||
|
|
||||||
|
* setuptools
|
||||||
|
* wheel
|
||||||
|
* twine
|
||||||
|
|
||||||
|
`python3 -m pip install --upgrade setuptools wheel twine`
|
||||||
|
|
||||||
|
|
||||||
|
## Mini-Tutorial
|
||||||
|
|
||||||
|
Have a look at the [Mini-Tutorial](tutorial.md)
|
||||||
|
|
||||||
|
|
||||||
|
## Release workflow
|
||||||
|
|
||||||
|
* `make build-ui` - in case there were any changes to the *.ui or *.qrc files
|
||||||
|
* make sure you have all changes added and commited (consider re-basing)
|
||||||
|
* update the version in `blitztui/version.py`
|
||||||
|
* update the `CHANGELOG.md` file (reflect the new version!)
|
||||||
|
* `git add CHANGELOG.md blitztui/version.py`
|
||||||
|
* `git commit` and set a proper commit message
|
||||||
|
* `make build`
|
||||||
|
* `make upload`
|
||||||
|
|
||||||
|
|
||||||
|
## Uploading to PyPI
|
||||||
|
|
||||||
|
Please use `twine` for uploading files to PyPI. You will need credentials for the BlitzTUI account.
|
||||||
|
|
||||||
|
```
|
||||||
|
$ cat ~/.pypirc
|
||||||
|
[distutils]
|
||||||
|
index-servers=
|
||||||
|
pypi
|
||||||
|
pypitest
|
||||||
|
|
||||||
|
[pypi]
|
||||||
|
username = RaspiBlitz
|
||||||
|
password = <REDACTED>
|
||||||
|
|
||||||
|
[pypitest]
|
||||||
|
repository = https://test.pypi.org/legacy/
|
||||||
|
username = RaspiBlitz-Test
|
||||||
|
password = <REDACTED>
|
||||||
|
```
|
||||||
|
|
||||||
|
## PRELOAD-What?!
|
||||||
|
|
||||||
|
**Update: This seems to be fixed since grpcio==1.24.3!**
|
||||||
|
|
||||||
|
What's the reason for this long `LD_PRELOAD` line?!
|
||||||
|
|
||||||
|
Apparently there is an incompatibility with the current version (as of writing this: **grpcio==1.24.1**) of
|
||||||
|
**gRPC** for Python on ARM (Raspberry Pi) that was released by Google. Running without `LD_PRELOAD` gives
|
||||||
|
an error regarding `undefined symbol: __atomic_exchange_8`:
|
||||||
|
|
||||||
|
```
|
||||||
|
(python3-env-lnd) admin@raspiblitz:~/raspiblitz/home.admin/BlitzTUI $ python3
|
||||||
|
Python 3.7.3 (default, Apr 3 2019, 05:39:12)
|
||||||
|
[GCC 8.2.0] on linux
|
||||||
|
Type "help", "copyright", "credits" or "license" for more information.
|
||||||
|
>>> import grpc
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "<stdin>", line 1, in <module>
|
||||||
|
File "/home/admin/python3-env-lnd/lib/python3.7/site-packages/grpc/__init__.py", line 23, in <module>
|
||||||
|
from grpc._cython import cygrpc as _cygrpc
|
||||||
|
ImportError: /home/admin/python3-env-lnd/lib/python3.7/site-packages/grpc/_cython/cygrpc.cpython-37m-arm-linux-gnueabihf.so: undefined symbol: __atomic_exchange_8
|
||||||
|
```
|
||||||
|
|
||||||
|
It is expected that this is resolved soon-ish.
|
||||||
|
|
||||||
|
|
||||||
|
## Directory tree
|
||||||
|
|
||||||
|
```
|
||||||
|
admin@raspiblitz:~/raspiblitz/home.admin/BlitzTUI $ tree
|
||||||
|
.
|
||||||
|
├── blitztui
|
||||||
|
│ ├── client.py
|
||||||
|
│ ├── config.py
|
||||||
|
│ ├── file_logger.py
|
||||||
|
│ ├── file_watcher.py
|
||||||
|
│ ├── __init__.py
|
||||||
|
│ ├── main.py
|
||||||
|
│ ├── memo.py
|
||||||
|
│ ├── ui
|
||||||
|
│ │ ├── home.py
|
||||||
|
│ │ ├── __init__.py
|
||||||
|
│ │ ├── invoice.py
|
||||||
|
│ │ ├── off.py
|
||||||
|
│ │ ├── qcode.py
|
||||||
|
│ │ └── resources_rc.py
|
||||||
|
│ └── version.py
|
||||||
|
├── CHANGELOG.md
|
||||||
|
├── data
|
||||||
|
│ ├── lnd.conf
|
||||||
|
│ ├── raspiblitz.conf
|
||||||
|
│ ├── raspiblitz.info
|
||||||
|
│ ├── Wordlist-Adjectives-Common-Audited-Len-3-6.txt
|
||||||
|
│ └── Wordlist-Nouns-Common-Audited-Len-3-6.txt
|
||||||
|
├── designer
|
||||||
|
│ ├── home.ui
|
||||||
|
│ ├── invoice.ui
|
||||||
|
│ ├── off.ui
|
||||||
|
│ └── qcode.ui
|
||||||
|
├── dist
|
||||||
|
├── docs
|
||||||
|
│ ├── images
|
||||||
|
│ │ └── QtDesigner.png
|
||||||
|
│ ├── README.md
|
||||||
|
│ └── tutorial.md
|
||||||
|
├── images
|
||||||
|
│ ├── blank_318x318.png
|
||||||
|
│ ├── Paid_Stamp.png
|
||||||
|
│ ├── RaspiBlitz_Logo_Berry.png
|
||||||
|
│ ├── RaspiBlitz_Logo_Condensed_270.png
|
||||||
|
│ ├── RaspiBlitz_Logo_Condensed_90.png
|
||||||
|
│ ├── RaspiBlitz_Logo_Condensed_Negative.png
|
||||||
|
│ ├── RaspiBlitz_Logo_Condensed.png
|
||||||
|
│ ├── RaspiBlitz_Logo_Icon_Negative.png
|
||||||
|
│ ├── RaspiBlitz_Logo_Icon.png
|
||||||
|
│ ├── RaspiBlitz_Logo_Main_270.png
|
||||||
|
│ ├── RaspiBlitz_Logo_Main_90.png
|
||||||
|
│ ├── RaspiBlitz_Logo_Main_Negative.png
|
||||||
|
│ ├── RaspiBlitz_Logo_Main.png
|
||||||
|
│ ├── RaspiBlitz_Logo_Stacked_270.png
|
||||||
|
│ ├── RaspiBlitz_Logo_Stacked_90.png
|
||||||
|
│ ├── RaspiBlitz_Logo_Stacked_Negative_270.png
|
||||||
|
│ ├── RaspiBlitz_Logo_Stacked_Negative_90.png
|
||||||
|
│ ├── RaspiBlitz_Logo_Stacked_Negative.png
|
||||||
|
│ └── RaspiBlitz_Logo_Stacked.png
|
||||||
|
├── LICENSE
|
||||||
|
├── make.cmd
|
||||||
|
├── Makefile
|
||||||
|
├── MANIFEST.in
|
||||||
|
├── README.md
|
||||||
|
├── requirements.txt
|
||||||
|
├── resources.qrc
|
||||||
|
├── setup.cfg
|
||||||
|
└── setup.py
|
||||||
|
```
|
BIN
home.admin/BlitzTUI/docs/images/QtDesigner.png
Normal file
After Width: | Height: | Size: 84 KiB |
47
home.admin/BlitzTUI/docs/tutorial.md
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
# BlitzTUI Mini-Tutorial
|
||||||
|
|
||||||
|
This *Mini-Tutorial* shows the basic workflow for doing changes to the Blitz-Touch-User-Interface.
|
||||||
|
|
||||||
|
## What you need
|
||||||
|
|
||||||
|
* A physical RaspiBlitz and SSH access to it (to verify your changes on the real screen)
|
||||||
|
* A Computer (Mac and Windows should work)
|
||||||
|
* The "Qt Designer" software (https://build-system.fman.io/qt-designer-download)
|
||||||
|
* A copy of the current RaspiBlitz codebase (`git clone https://github.com/rootzoll/raspiblitz.git`)
|
||||||
|
|
||||||
|
## Scenario
|
||||||
|
|
||||||
|
Let's assume you want to reduce the width of the button row on the left side.
|
||||||
|
|
||||||
|
* Open Qt Designer
|
||||||
|
* Load the .ui file: `home.admin/BlitzTUI/designer/home.ui`
|
||||||
|
|
||||||
|
Your screen should look similar to this:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
* (1) for this scenario go to the **Object Inspector** and select **splitter**
|
||||||
|
* (2) change the **Width** (e.g. from 80 to 60)
|
||||||
|
* (3) this should be reflected in the preview Window
|
||||||
|
* (4) save your changes
|
||||||
|
|
||||||
|
The next step is to transfer (use scp or WinSCP) the updated `home.ui` to the RaspiBlitz.
|
||||||
|
|
||||||
|
Login to your RaspiBlitz as **admin** (Password A) and change the directory to `~/raspiblitz/home.admin/BlitzTUI`.
|
||||||
|
|
||||||
|
Your updated `home.ui` file should be in `designer/` (confirm timestamp with `ls -l designer/home.ui`).
|
||||||
|
|
||||||
|
Run `make build-ui`
|
||||||
|
|
||||||
|
To quickly check the result run
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo -u pi DISPLAY=:0.0 LD_PRELOAD=/usr/lib/arm-linux-gnueabihf/libatomic.so.1.2.0 /home/admin/python3-env-lnd/bin/python3 /home/admin/raspiblitz/home.admin/BlitzTUI/blitztui/main.py
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also install the current directory as a python package using `pip install -e .` and the run
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo -u pi DISPLAY=:0.0 LD_PRELOAD=/usr/lib/arm-linux-gnueabihf/libatomic.so.1.2.0 /home/admin/python3-env-lnd/bin/blitz-tui
|
||||||
|
```
|
||||||
|
|
BIN
home.admin/BlitzTUI/images/Paid_Stamp.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
home.admin/BlitzTUI/images/RaspiBlitz_Logo_Berry.png
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
home.admin/BlitzTUI/images/RaspiBlitz_Logo_Condensed.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
home.admin/BlitzTUI/images/RaspiBlitz_Logo_Condensed_270.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
home.admin/BlitzTUI/images/RaspiBlitz_Logo_Condensed_90.png
Normal file
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 14 KiB |
BIN
home.admin/BlitzTUI/images/RaspiBlitz_Logo_Icon.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
home.admin/BlitzTUI/images/RaspiBlitz_Logo_Icon_Negative.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
BIN
home.admin/BlitzTUI/images/RaspiBlitz_Logo_Main.png
Normal file
After Width: | Height: | Size: 39 KiB |
BIN
home.admin/BlitzTUI/images/RaspiBlitz_Logo_Main_270.png
Normal file
After Width: | Height: | Size: 27 KiB |
BIN
home.admin/BlitzTUI/images/RaspiBlitz_Logo_Main_90.png
Normal file
After Width: | Height: | Size: 27 KiB |
BIN
home.admin/BlitzTUI/images/RaspiBlitz_Logo_Main_Negative.png
Normal file
After Width: | Height: | Size: 39 KiB |
BIN
home.admin/BlitzTUI/images/RaspiBlitz_Logo_Stacked.png
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
home.admin/BlitzTUI/images/RaspiBlitz_Logo_Stacked_270.png
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
home.admin/BlitzTUI/images/RaspiBlitz_Logo_Stacked_90.png
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
home.admin/BlitzTUI/images/RaspiBlitz_Logo_Stacked_Negative.png
Normal file
After Width: | Height: | Size: 38 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 30 KiB |
BIN
home.admin/BlitzTUI/images/blank_318x318.png
Normal file
After Width: | Height: | Size: 1005 B |
10
home.admin/BlitzTUI/make.cmd
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
REM run this from BlitzTUI directory
|
||||||
|
|
||||||
|
REM convert ui files to python code
|
||||||
|
pyuic5 -x --import-from "." -o blitztui/ui/qcode.py designer/qcode.ui
|
||||||
|
pyuic5 -x --import-from "." -o blitztui/ui/home.py designer/home.ui
|
||||||
|
pyuic5 -x --import-from "." -o blitztui/ui/off.py designer/off.ui
|
||||||
|
pyuic5 -x --import-from "." -o blitztui/ui/invoice.py designer/invoice.ui
|
||||||
|
|
||||||
|
REM resources
|
||||||
|
pyrcc5 -o blitztui/ui/resources_rc.py resources.qrc
|
6
home.admin/BlitzTUI/requirements.txt
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
grpcio>=1.24.3
|
||||||
|
googleapis-common-protos>=1.6.0
|
||||||
|
inotify>=0.2
|
||||||
|
psutil>=5.6
|
||||||
|
pyqtspinner>=0.1
|
||||||
|
qrcode>=6.1
|
23
home.admin/BlitzTUI/resources.qrc
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<RCC>
|
||||||
|
<qresource prefix="RaspiBlitz">
|
||||||
|
<file>images/blank_318x318.png</file>
|
||||||
|
<file>images/Paid_Stamp.png</file>
|
||||||
|
<file>images/RaspiBlitz_Logo_Berry.png</file>
|
||||||
|
<file>images/RaspiBlitz_Logo_Condensed.png</file>
|
||||||
|
<file>images/RaspiBlitz_Logo_Condensed_90.png</file>
|
||||||
|
<file>images/RaspiBlitz_Logo_Condensed_270.png</file>
|
||||||
|
<file>images/RaspiBlitz_Logo_Condensed_Negative.png</file>
|
||||||
|
<file>images/RaspiBlitz_Logo_Icon.png</file>
|
||||||
|
<file>images/RaspiBlitz_Logo_Icon_Negative.png</file>
|
||||||
|
<file>images/RaspiBlitz_Logo_Main.png</file>
|
||||||
|
<file>images/RaspiBlitz_Logo_Main_90.png</file>
|
||||||
|
<file>images/RaspiBlitz_Logo_Main_270.png</file>
|
||||||
|
<file>images/RaspiBlitz_Logo_Main_Negative.png</file>
|
||||||
|
<file>images/RaspiBlitz_Logo_Stacked.png</file>
|
||||||
|
<file>images/RaspiBlitz_Logo_Stacked_90.png</file>
|
||||||
|
<file>images/RaspiBlitz_Logo_Stacked_270.png</file>
|
||||||
|
<file>images/RaspiBlitz_Logo_Stacked_Negative.png</file>
|
||||||
|
<file>images/RaspiBlitz_Logo_Stacked_Negative_90.png</file>
|
||||||
|
<file>images/RaspiBlitz_Logo_Stacked_Negative_270.png</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
6
home.admin/BlitzTUI/setup.cfg
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# content of setup.cfg
|
||||||
|
[tool:pytest]
|
||||||
|
addopts = -ra -q
|
||||||
|
|
||||||
|
[bdist_wheel]
|
||||||
|
universal = 1
|
39
home.admin/BlitzTUI/setup.py
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import setuptools
|
||||||
|
|
||||||
|
with open("README.md", "r") as fh:
|
||||||
|
long_description = fh.read()
|
||||||
|
|
||||||
|
with open("blitztui/version.py") as f:
|
||||||
|
__version__ = ""
|
||||||
|
exec(f.read()) # set __version__
|
||||||
|
|
||||||
|
setuptools.setup(
|
||||||
|
name="BlitzTUI",
|
||||||
|
version=__version__,
|
||||||
|
author="RaspiBlitz Developers",
|
||||||
|
author_email="raspiblitz@rhab.de",
|
||||||
|
description="Touch User Interface for RaspiBlitz",
|
||||||
|
long_description=long_description,
|
||||||
|
long_description_content_type="text/markdown",
|
||||||
|
url="https://github.com/rootzoll/raspiblitz",
|
||||||
|
packages=setuptools.find_packages(exclude=("tests", "docs")),
|
||||||
|
classifiers=[
|
||||||
|
# How mature is this project? Common values are
|
||||||
|
# 3 - Alpha
|
||||||
|
# 4 - Beta
|
||||||
|
# 5 - Production/Stable
|
||||||
|
"Development Status :: 4 - Beta",
|
||||||
|
|
||||||
|
"Programming Language :: Python :: 3",
|
||||||
|
"License :: OSI Approved :: MIT License",
|
||||||
|
"Operating System :: POSIX :: Linux",
|
||||||
|
],
|
||||||
|
python_requires='>=3.4',
|
||||||
|
install_requires=[
|
||||||
|
"grpcio", "googleapis-common-protos", "inotify", "psutil", "pyqtspinner", "qrcode",
|
||||||
|
],
|
||||||
|
entry_points={
|
||||||
|
'console_scripts': ['blitz-tui=blitztui.main:main'],
|
||||||
|
},
|
||||||
|
)
|
@ -1,11 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "Thanks"
|
|
||||||
echo "You pressed B2"
|
|
||||||
echo "-----------------------------------------------"
|
|
||||||
echo "Sleep for 10"
|
|
||||||
sleep 10
|
|
||||||
echo "Goodbye"
|
|
||||||
echo "-----------------------------------------------"
|
|
||||||
exit 0
|
|
@ -70,4 +70,4 @@ sudo -u admin chmod +x /home/admin/config.scripts/*.py
|
|||||||
echo "******************************************"
|
echo "******************************************"
|
||||||
echo "OK - shell scripts and assests are synced"
|
echo "OK - shell scripts and assests are synced"
|
||||||
echo "Reboot recommended"
|
echo "Reboot recommended"
|
||||||
echo ""
|
echo ""
|
||||||
|
@ -15,10 +15,6 @@ if [ $# -eq 0 ] || [ "$1" = "-h" ] || [ "$1" = "-help" ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# update install sources
|
|
||||||
echo "make sure dependencies are installed ..."
|
|
||||||
sudo apt-get install -y unclutter xterm
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
###################
|
###################
|
||||||
# SWITCH ON
|
# SWITCH ON
|
||||||
@ -28,13 +24,37 @@ if [ "$1" = "1" ] || [ "$1" = "on" ]; then
|
|||||||
|
|
||||||
echo "Turn ON: Touchscreen"
|
echo "Turn ON: Touchscreen"
|
||||||
|
|
||||||
|
# update install sources
|
||||||
|
echo "make sure dependencies are installed ..."
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y unclutter xterm
|
||||||
|
# TODO(frennkie) should this be removed when running "off"?
|
||||||
|
sudo apt-get install -y python3-pyqt5
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo "installing BlitzTUI (including dependencies)"
|
||||||
|
/home/admin/python3-env-lnd/bin/pip install BlitzTUI
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# patch lndlibs for Python3
|
||||||
|
if ! grep -Fxq "from __future__ import absolute_import" /home/admin/config.scripts/lndlibs/rpc_pb2_grpc.py; then
|
||||||
|
sed -i -E '1 a from __future__ import absolute_import' /home/admin/config.scripts/lndlibs/rpc_pb2_grpc.py
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! grep -Eq "^from . import.*" /home/admin/config.scripts/lndlibs/rpc_pb2_grpc.py; then
|
||||||
|
sed -i -E 's/^(import.*_pb2)/from . \1/' /home/admin/config.scripts/lndlibs/rpc_pb2_grpc.py
|
||||||
|
fi
|
||||||
|
|
||||||
# switch to desktop login
|
# switch to desktop login
|
||||||
sudo raspi-config nonint do_boot_behaviour B4
|
sudo raspi-config nonint do_boot_behaviour B4
|
||||||
|
|
||||||
# set user pi user for autostart
|
# set user pi user for autostart
|
||||||
sudo sed -i "s/^autologin-user=.*/autologin-user=pi/g" /etc/lightdm/lightdm.conf
|
sudo sed -i 's/^autologin-user=.*/autologin-user=pi/g' /etc/lightdm/lightdm.conf
|
||||||
sudo sed -i s'/--autologin root/--autologin pi/' /etc/systemd/system/getty@tty1.service.d/autologin.conf
|
sudo sed -i 's/--autologin root/--autologin pi/' /etc/systemd/system/getty@tty1.service.d/autologin.conf
|
||||||
sudo sed -i s'/--autologin admin/--autologin pi/' /etc/systemd/system/getty@tty1.service.d/autologin.conf
|
sudo sed -i 's/--autologin admin/--autologin pi/' /etc/systemd/system/getty@tty1.service.d/autologin.conf
|
||||||
|
|
||||||
|
# remove welcome wizard
|
||||||
|
sudo rm -rf /etc/xdg/autostart/piwiz.desktop
|
||||||
|
|
||||||
# write new LXDE autostart config
|
# write new LXDE autostart config
|
||||||
sudo mv /etc/xdg/lxsession/LXDE-pi/autostart /etc/xdg/lxsession/LXDE-pi/autostart.bak
|
sudo mv /etc/xdg/lxsession/LXDE-pi/autostart /etc/xdg/lxsession/LXDE-pi/autostart.bak
|
||||||
@ -49,8 +69,9 @@ EOF
|
|||||||
# editing autostart.sh
|
# editing autostart.sh
|
||||||
cat << EOF | sudo tee /home/pi/autostart.sh >/dev/null
|
cat << EOF | sudo tee /home/pi/autostart.sh >/dev/null
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
sleep 1
|
|
||||||
/usr/bin/python3 /home/admin/00infoLCDTK.py
|
unset QT_QPA_PLATFORMTHEME
|
||||||
|
/home/admin/python3-env-lnd/bin/blitz-tui
|
||||||
EOF
|
EOF
|
||||||
sudo chmod a+x /home/pi/autostart.sh
|
sudo chmod a+x /home/pi/autostart.sh
|
||||||
sudo chown pi:pi /home/pi/autostart.sh
|
sudo chown pi:pi /home/pi/autostart.sh
|
||||||
@ -58,6 +79,24 @@ EOF
|
|||||||
# Remove 00infoLCD.sh from .bashrc of pi user
|
# Remove 00infoLCD.sh from .bashrc of pi user
|
||||||
sudo sed -i s'/exec $SCRIPT/#exec $SCRIPT/' /home/pi/.bashrc
|
sudo sed -i s'/exec $SCRIPT/#exec $SCRIPT/' /home/pi/.bashrc
|
||||||
|
|
||||||
|
# adapt design by changing openbox settings
|
||||||
|
sudo sed -i -E 's/<weight>Normal</<weight>Bold</g' /etc/xdg/openbox/lxde-pi-rc.xml
|
||||||
|
sudo sed -i -E 's/<name>PibotoLt</<name>Arial</g' /etc/xdg/openbox/lxde-pi-rc.xml
|
||||||
|
sudo sed -i -E 's/window.active.title.bg.color: #87919B/window.active.title.bg.color: #000046/' /usr/share/themes/PiXflat/openbox-3/themerc
|
||||||
|
sudo sed -i -E 's/window.inactive.title.bg.color: #EEEFEE/window.inactive.title.bg.color: #000046/' /usr/share/themes/PiXflat/openbox-3/themerc
|
||||||
|
|
||||||
|
# remove minimize, maximize, close from titlebar
|
||||||
|
sudo sed -i -E 's/titleLayout>LIMC/titleLayout>L/g' /etc/xdg/openbox/lxde-pi-rc.xml
|
||||||
|
|
||||||
|
# Copy over the macaroons
|
||||||
|
sudo mkdir -p /home/pi/.lnd/data/chain/bitcoin/mainnet/
|
||||||
|
sudo chmod 700 /home/pi/.lnd/
|
||||||
|
sudo ln -s /home/admin/.lnd/tls.cert /home/pi/.lnd/
|
||||||
|
sudo cp /home/admin/.lnd/data/chain/bitcoin/mainnet/readonly.macaroon /home/pi/.lnd/data/chain/bitcoin/mainnet/
|
||||||
|
sudo cp /home/admin/.lnd/data/chain/bitcoin/mainnet/invoice.macaroon /home/pi/.lnd/data/chain/bitcoin/mainnet/
|
||||||
|
sudo chmod 600 /home/pi/.lnd/data/chain/bitcoin/mainnet/*.macaroon
|
||||||
|
sudo chown -R pi:pi /home/pi/.lnd/
|
||||||
|
|
||||||
# rotate touchscreen based on if LCD is rotated
|
# rotate touchscreen based on if LCD is rotated
|
||||||
if [ "${lcdrotate}" = "1" ]; then
|
if [ "${lcdrotate}" = "1" ]; then
|
||||||
echo "LCD is rotated into default - no touchscreen rotate"
|
echo "LCD is rotated into default - no touchscreen rotate"
|
||||||
@ -100,7 +139,7 @@ if [ "$1" = "0" ] || [ "$1" = "off" ]; then
|
|||||||
sudo sed -i s'/--autologin admin/--autologin pi/' /etc/systemd/system/getty@tty1.service.d/autologin.conf
|
sudo sed -i s'/--autologin admin/--autologin pi/' /etc/systemd/system/getty@tty1.service.d/autologin.conf
|
||||||
|
|
||||||
# move back old LXDE autostart config
|
# move back old LXDE autostart config
|
||||||
sudp rm /etc/xdg/lxsession/LXDE-pi/autostart
|
sudo rm /etc/xdg/lxsession/LXDE-pi/autostart
|
||||||
sudo mv /etc/xdg/lxsession/LXDE-pi/autostart.bak /etc/xdg/lxsession/LXDE-pi/autostart
|
sudo mv /etc/xdg/lxsession/LXDE-pi/autostart.bak /etc/xdg/lxsession/LXDE-pi/autostart
|
||||||
|
|
||||||
# add again 00infoLCD.sh to .bashrc of pi user
|
# add again 00infoLCD.sh to .bashrc of pi user
|
||||||
|
@ -175,7 +175,7 @@ message UnlockWalletRequest {
|
|||||||
/**
|
/**
|
||||||
recovery_window is an optional argument specifying the address lookahead
|
recovery_window is an optional argument specifying the address lookahead
|
||||||
when restoring a wallet seed. The recovery window applies to each
|
when restoring a wallet seed. The recovery window applies to each
|
||||||
invdividual branch of the BIP44 derivation paths. Supplying a recovery
|
individual branch of the BIP44 derivation paths. Supplying a recovery
|
||||||
window of zero indicates that no addresses should be recovered, such after
|
window of zero indicates that no addresses should be recovered, such after
|
||||||
the first initialization of the wallet.
|
the first initialization of the wallet.
|
||||||
*/
|
*/
|
||||||
@ -212,7 +212,7 @@ service Lightning {
|
|||||||
/** lncli: `walletbalance`
|
/** lncli: `walletbalance`
|
||||||
WalletBalance returns total unspent outputs(confirmed and unconfirmed), all
|
WalletBalance returns total unspent outputs(confirmed and unconfirmed), all
|
||||||
confirmed unspent outputs and all unconfirmed unspent outputs under control
|
confirmed unspent outputs and all unconfirmed unspent outputs under control
|
||||||
of the wallet.
|
of the wallet.
|
||||||
*/
|
*/
|
||||||
rpc WalletBalance (WalletBalanceRequest) returns (WalletBalanceResponse) {
|
rpc WalletBalance (WalletBalanceRequest) returns (WalletBalanceResponse) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
@ -389,7 +389,7 @@ service Lightning {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/** lncli: `subscribechannelevents`
|
/**
|
||||||
SubscribeChannelEvents creates a uni-directional stream from the server to
|
SubscribeChannelEvents creates a uni-directional stream from the server to
|
||||||
the client in which any updates relevant to the state of the channels are
|
the client in which any updates relevant to the state of the channels are
|
||||||
sent over. Events include new active channels, inactive channels, and closed
|
sent over. Events include new active channels, inactive channels, and closed
|
||||||
@ -398,7 +398,7 @@ service Lightning {
|
|||||||
rpc SubscribeChannelEvents (ChannelEventSubscription) returns (stream ChannelEventUpdate);
|
rpc SubscribeChannelEvents (ChannelEventSubscription) returns (stream ChannelEventUpdate);
|
||||||
|
|
||||||
/** lncli: `closedchannels`
|
/** lncli: `closedchannels`
|
||||||
ClosedChannels returns a description of all the closed channels that
|
ClosedChannels returns a description of all the closed channels that
|
||||||
this node was a participant in.
|
this node was a participant in.
|
||||||
*/
|
*/
|
||||||
rpc ClosedChannels (ClosedChannelsRequest) returns (ClosedChannelsResponse) {
|
rpc ClosedChannels (ClosedChannelsRequest) returns (ClosedChannelsResponse) {
|
||||||
@ -430,6 +430,15 @@ service Lightning {
|
|||||||
*/
|
*/
|
||||||
rpc OpenChannel (OpenChannelRequest) returns (stream OpenStatusUpdate);
|
rpc OpenChannel (OpenChannelRequest) returns (stream OpenStatusUpdate);
|
||||||
|
|
||||||
|
/**
|
||||||
|
ChannelAcceptor dispatches a bi-directional streaming RPC in which
|
||||||
|
OpenChannel requests are sent to the client and the client responds with
|
||||||
|
a boolean that tells LND whether or not to accept the channel. This allows
|
||||||
|
node operators to specify their own criteria for accepting inbound channels
|
||||||
|
through a single persistent connection.
|
||||||
|
*/
|
||||||
|
rpc ChannelAcceptor (stream ChannelAcceptResponse) returns (stream ChannelAcceptRequest);
|
||||||
|
|
||||||
/** lncli: `closechannel`
|
/** lncli: `closechannel`
|
||||||
CloseChannel attempts to close an active channel identified by its channel
|
CloseChannel attempts to close an active channel identified by its channel
|
||||||
outpoint (ChannelPoint). The actions of this method can additionally be
|
outpoint (ChannelPoint). The actions of this method can additionally be
|
||||||
@ -621,7 +630,7 @@ service Lightning {
|
|||||||
/** lncli: `queryroutes`
|
/** lncli: `queryroutes`
|
||||||
QueryRoutes attempts to query the daemon's Channel Router for a possible
|
QueryRoutes attempts to query the daemon's Channel Router for a possible
|
||||||
route to a target destination capable of carrying a specific amount of
|
route to a target destination capable of carrying a specific amount of
|
||||||
satoshis. The retuned route contains the full details required to craft and
|
satoshis. The returned route contains the full details required to craft and
|
||||||
send an HTLC, also including the necessary information that should be
|
send an HTLC, also including the necessary information that should be
|
||||||
present within the Sphinx packet encapsulated within the HTLC.
|
present within the Sphinx packet encapsulated within the HTLC.
|
||||||
*/
|
*/
|
||||||
@ -768,6 +777,18 @@ service Lightning {
|
|||||||
*/
|
*/
|
||||||
rpc SubscribeChannelBackups(ChannelBackupSubscription) returns (stream ChanBackupSnapshot) {
|
rpc SubscribeChannelBackups(ChannelBackupSubscription) returns (stream ChanBackupSnapshot) {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** lncli: `bakemacaroon`
|
||||||
|
BakeMacaroon allows the creation of a new macaroon with custom read and
|
||||||
|
write permissions. No first-party caveats are added since this can be done
|
||||||
|
offline.
|
||||||
|
*/
|
||||||
|
rpc BakeMacaroon(BakeMacaroonRequest) returns (BakeMacaroonResponse) {
|
||||||
|
option (google.api.http) = {
|
||||||
|
post: "/v1/macaroon"
|
||||||
|
body: "*"
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
message Utxo {
|
message Utxo {
|
||||||
@ -814,6 +835,9 @@ message Transaction {
|
|||||||
|
|
||||||
/// Addresses that received funds for this transaction
|
/// Addresses that received funds for this transaction
|
||||||
repeated string dest_addresses = 8 [ json_name = "dest_addresses" ];
|
repeated string dest_addresses = 8 [ json_name = "dest_addresses" ];
|
||||||
|
|
||||||
|
/// The raw transaction hex.
|
||||||
|
string raw_tx_hex = 9 [ json_name = "raw_tx_hex" ];
|
||||||
}
|
}
|
||||||
message GetTransactionsRequest {
|
message GetTransactionsRequest {
|
||||||
}
|
}
|
||||||
@ -873,13 +897,21 @@ message SendRequest {
|
|||||||
The channel id of the channel that must be taken to the first hop. If zero,
|
The channel id of the channel that must be taken to the first hop. If zero,
|
||||||
any channel may be used.
|
any channel may be used.
|
||||||
*/
|
*/
|
||||||
uint64 outgoing_chan_id = 9;
|
uint64 outgoing_chan_id = 9 [jstype = JS_STRING];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
An optional maximum total time lock for the route. If zero, there is no
|
An optional maximum total time lock for the route. This should not exceed
|
||||||
maximum enforced.
|
lnd's `--max-cltv-expiry` setting. If zero, then the value of
|
||||||
|
`--max-cltv-expiry` is enforced.
|
||||||
*/
|
*/
|
||||||
uint32 cltv_limit = 10;
|
uint32 cltv_limit = 10;
|
||||||
|
|
||||||
|
/**
|
||||||
|
An optional field that can be used to pass an arbitrary set of TLV records
|
||||||
|
to a peer which understands the new records. This can be used to pass
|
||||||
|
application specific data during the payment attempt.
|
||||||
|
*/
|
||||||
|
map<uint64, bytes> dest_tlv = 11;
|
||||||
}
|
}
|
||||||
|
|
||||||
message SendResponse {
|
message SendResponse {
|
||||||
@ -896,18 +928,64 @@ message SendToRouteRequest {
|
|||||||
/// An optional hex-encoded payment hash to be used for the HTLC.
|
/// An optional hex-encoded payment hash to be used for the HTLC.
|
||||||
string payment_hash_string = 2;
|
string payment_hash_string = 2;
|
||||||
|
|
||||||
/**
|
reserved 3;
|
||||||
Deprecated. The set of routes that should be used to attempt to complete the
|
|
||||||
payment. The possibility to pass in multiple routes is deprecated and
|
|
||||||
instead the single route field below should be used in combination with the
|
|
||||||
streaming variant of SendToRoute.
|
|
||||||
*/
|
|
||||||
repeated Route routes = 3 [deprecated = true];
|
|
||||||
|
|
||||||
/// Route that should be used to attempt to complete the payment.
|
/// Route that should be used to attempt to complete the payment.
|
||||||
Route route = 4;
|
Route route = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message ChannelAcceptRequest {
|
||||||
|
/// The pubkey of the node that wishes to open an inbound channel.
|
||||||
|
bytes node_pubkey = 1;
|
||||||
|
|
||||||
|
/// The hash of the genesis block that the proposed channel resides in.
|
||||||
|
bytes chain_hash = 2;
|
||||||
|
|
||||||
|
/// The pending channel id.
|
||||||
|
bytes pending_chan_id = 3;
|
||||||
|
|
||||||
|
/// The funding amount in satoshis that initiator wishes to use in the channel.
|
||||||
|
uint64 funding_amt = 4;
|
||||||
|
|
||||||
|
/// The push amount of the proposed channel in millisatoshis.
|
||||||
|
uint64 push_amt = 5;
|
||||||
|
|
||||||
|
/// The dust limit of the initiator's commitment tx.
|
||||||
|
uint64 dust_limit = 6;
|
||||||
|
|
||||||
|
/// The maximum amount of coins in millisatoshis that can be pending in this channel.
|
||||||
|
uint64 max_value_in_flight = 7;
|
||||||
|
|
||||||
|
/// The minimum amount of satoshis the initiator requires us to have at all times.
|
||||||
|
uint64 channel_reserve = 8;
|
||||||
|
|
||||||
|
/// The smallest HTLC in millisatoshis that the initiator will accept.
|
||||||
|
uint64 min_htlc = 9;
|
||||||
|
|
||||||
|
/// The initial fee rate that the initiator suggests for both commitment transactions.
|
||||||
|
uint64 fee_per_kw = 10;
|
||||||
|
|
||||||
|
/**
|
||||||
|
The number of blocks to use for the relative time lock in the pay-to-self output
|
||||||
|
of both commitment transactions.
|
||||||
|
*/
|
||||||
|
uint32 csv_delay = 11;
|
||||||
|
|
||||||
|
/// The total number of incoming HTLC's that the initiator will accept.
|
||||||
|
uint32 max_accepted_htlcs = 12;
|
||||||
|
|
||||||
|
/// A bit-field which the initiator uses to specify proposed channel behavior.
|
||||||
|
uint32 channel_flags = 13;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ChannelAcceptResponse {
|
||||||
|
/// Whether or not the client accepts the channel.
|
||||||
|
bool accept = 1;
|
||||||
|
|
||||||
|
/// The pending channel id to which this response applies.
|
||||||
|
bytes pending_chan_id = 2;
|
||||||
|
}
|
||||||
|
|
||||||
message ChannelPoint {
|
message ChannelPoint {
|
||||||
oneof funding_txid {
|
oneof funding_txid {
|
||||||
/// Txid of the funding transaction
|
/// Txid of the funding transaction
|
||||||
@ -1098,7 +1176,7 @@ message Channel {
|
|||||||
height, the next 3 the index within the block, and the last 2 bytes are the
|
height, the next 3 the index within the block, and the last 2 bytes are the
|
||||||
output index for the channel.
|
output index for the channel.
|
||||||
*/
|
*/
|
||||||
uint64 chan_id = 4 [json_name = "chan_id"];
|
uint64 chan_id = 4 [json_name = "chan_id", jstype = JS_STRING];
|
||||||
|
|
||||||
/// The total amount of funds held in this channel
|
/// The total amount of funds held in this channel
|
||||||
int64 capacity = 5 [json_name = "capacity"];
|
int64 capacity = 5 [json_name = "capacity"];
|
||||||
@ -1162,8 +1240,37 @@ message Channel {
|
|||||||
/// True if we were the ones that created the channel.
|
/// True if we were the ones that created the channel.
|
||||||
bool initiator = 18 [json_name = "initiator"];
|
bool initiator = 18 [json_name = "initiator"];
|
||||||
|
|
||||||
/// A set of flags showing the current state of the cahnnel.
|
/// A set of flags showing the current state of the channel.
|
||||||
string chan_status_flags = 19 [json_name = "chan_status_flags"];
|
string chan_status_flags = 19 [json_name = "chan_status_flags"];
|
||||||
|
|
||||||
|
/// The minimum satoshis this node is required to reserve in its balance.
|
||||||
|
int64 local_chan_reserve_sat = 20 [json_name = "local_chan_reserve_sat"];
|
||||||
|
|
||||||
|
/**
|
||||||
|
The minimum satoshis the other node is required to reserve in its balance.
|
||||||
|
*/
|
||||||
|
int64 remote_chan_reserve_sat = 21 [json_name = "remote_chan_reserve_sat"];
|
||||||
|
|
||||||
|
/**
|
||||||
|
If true, then this channel uses the modern commitment format where the key
|
||||||
|
in the output of the remote party does not change each state. This makes
|
||||||
|
back up and recovery easier as when the channel is closed, the funds go
|
||||||
|
directly to that key.
|
||||||
|
*/
|
||||||
|
bool static_remote_key = 22 [json_name = "static_remote_key"];
|
||||||
|
|
||||||
|
/**
|
||||||
|
The number of seconds that the channel has been monitored by the channel
|
||||||
|
scoring system. Scores are currently not persisted, so this value may be
|
||||||
|
less than the lifetime of the channel [EXPERIMENTAL].
|
||||||
|
*/
|
||||||
|
int64 lifetime = 23 [json_name = "lifetime"];
|
||||||
|
|
||||||
|
/**
|
||||||
|
The number of seconds that the remote peer has been observed as being online
|
||||||
|
by the channel scoring system over the lifetime of the channel [EXPERIMENTAL].
|
||||||
|
*/
|
||||||
|
int64 uptime = 24 [json_name = "uptime"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1183,7 +1290,7 @@ message ChannelCloseSummary {
|
|||||||
string channel_point = 1 [json_name = "channel_point"];
|
string channel_point = 1 [json_name = "channel_point"];
|
||||||
|
|
||||||
/// The unique channel ID for the channel.
|
/// The unique channel ID for the channel.
|
||||||
uint64 chan_id = 2 [json_name = "chan_id"];
|
uint64 chan_id = 2 [json_name = "chan_id", jstype = JS_STRING];
|
||||||
|
|
||||||
/// The hash of the genesis block that this channel resides within.
|
/// The hash of the genesis block that this channel resides within.
|
||||||
string chain_hash = 3 [json_name = "chain_hash"];
|
string chain_hash = 3 [json_name = "chain_hash"];
|
||||||
@ -1335,6 +1442,12 @@ message GetInfoResponse {
|
|||||||
|
|
||||||
/// A list of active chains the node is connected to
|
/// A list of active chains the node is connected to
|
||||||
repeated Chain chains = 16 [json_name = "chains"];
|
repeated Chain chains = 16 [json_name = "chains"];
|
||||||
|
|
||||||
|
/// The color of the current node in hex code format
|
||||||
|
string color = 17 [json_name = "color"];
|
||||||
|
|
||||||
|
// Whether we consider ourselves synced with the public channel graph.
|
||||||
|
bool synced_to_graph = 18 [json_name = "synced_to_graph"];
|
||||||
}
|
}
|
||||||
|
|
||||||
message Chain {
|
message Chain {
|
||||||
@ -1468,6 +1581,15 @@ message PendingChannelsResponse {
|
|||||||
|
|
||||||
int64 local_balance = 4 [ json_name = "local_balance" ];
|
int64 local_balance = 4 [ json_name = "local_balance" ];
|
||||||
int64 remote_balance = 5 [ json_name = "remote_balance" ];
|
int64 remote_balance = 5 [ json_name = "remote_balance" ];
|
||||||
|
|
||||||
|
/// The minimum satoshis this node is required to reserve in its balance.
|
||||||
|
int64 local_chan_reserve_sat = 6 [json_name = "local_chan_reserve_sat"];
|
||||||
|
|
||||||
|
/**
|
||||||
|
The minimum satoshis the other node is required to reserve in its
|
||||||
|
balance.
|
||||||
|
*/
|
||||||
|
int64 remote_chan_reserve_sat = 7 [json_name = "remote_chan_reserve_sat"];
|
||||||
}
|
}
|
||||||
|
|
||||||
message PendingOpenChannel {
|
message PendingOpenChannel {
|
||||||
@ -1523,7 +1645,7 @@ message PendingChannelsResponse {
|
|||||||
/// The balance in satoshis encumbered in this pending channel
|
/// The balance in satoshis encumbered in this pending channel
|
||||||
int64 limbo_balance = 3 [ json_name = "limbo_balance" ];
|
int64 limbo_balance = 3 [ json_name = "limbo_balance" ];
|
||||||
|
|
||||||
/// The height at which funds can be sweeped into the wallet
|
/// The height at which funds can be swept into the wallet
|
||||||
uint32 maturity_height = 4 [ json_name = "maturity_height" ];
|
uint32 maturity_height = 4 [ json_name = "maturity_height" ];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1606,11 +1728,7 @@ message QueryRoutesRequest {
|
|||||||
/// The amount to send expressed in satoshis
|
/// The amount to send expressed in satoshis
|
||||||
int64 amt = 2;
|
int64 amt = 2;
|
||||||
|
|
||||||
/**
|
reserved 3;
|
||||||
Deprecated. The max number of routes to return. In the future, QueryRoutes
|
|
||||||
will only return a single route.
|
|
||||||
*/
|
|
||||||
int32 num_routes = 3 [deprecated = true];
|
|
||||||
|
|
||||||
/// An optional CLTV delta from the current height that should be used for the timelock of the final hop
|
/// An optional CLTV delta from the current height that should be used for the timelock of the final hop
|
||||||
int32 final_cltv_delta = 4;
|
int32 final_cltv_delta = 4;
|
||||||
@ -1629,20 +1747,46 @@ message QueryRoutesRequest {
|
|||||||
repeated bytes ignored_nodes = 6;
|
repeated bytes ignored_nodes = 6;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
A list of edges to ignore during path finding.
|
Deprecated. A list of edges to ignore during path finding.
|
||||||
*/
|
*/
|
||||||
repeated EdgeLocator ignored_edges = 7;
|
repeated EdgeLocator ignored_edges = 7 [deprecated = true];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The source node where the request route should originated from. If empty,
|
The source node where the request route should originated from. If empty,
|
||||||
self is assumed.
|
self is assumed.
|
||||||
*/
|
*/
|
||||||
string source_pub_key = 8;
|
string source_pub_key = 8;
|
||||||
|
|
||||||
|
/**
|
||||||
|
If set to true, edge probabilities from mission control will be used to get
|
||||||
|
the optimal route.
|
||||||
|
*/
|
||||||
|
bool use_mission_control = 9;
|
||||||
|
|
||||||
|
/**
|
||||||
|
A list of directed node pairs that will be ignored during path finding.
|
||||||
|
*/
|
||||||
|
repeated NodePair ignored_pairs = 10;
|
||||||
|
|
||||||
|
/**
|
||||||
|
An optional maximum total time lock for the route. If the source is empty or
|
||||||
|
ourselves, this should not exceed lnd's `--max-cltv-expiry` setting. If
|
||||||
|
zero, then the value of `--max-cltv-expiry` is used as the limit.
|
||||||
|
*/
|
||||||
|
uint32 cltv_limit = 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
message NodePair {
|
||||||
|
/// The sending node of the pair.
|
||||||
|
bytes from = 1;
|
||||||
|
|
||||||
|
/// The receiving node of the pair.
|
||||||
|
bytes to = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message EdgeLocator {
|
message EdgeLocator {
|
||||||
/// The short channel id of this edge.
|
/// The short channel id of this edge.
|
||||||
uint64 channel_id = 1;
|
uint64 channel_id = 1 [jstype = JS_STRING];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The direction of this edge. If direction_reverse is false, the direction
|
The direction of this edge. If direction_reverse is false, the direction
|
||||||
@ -1654,7 +1798,17 @@ message EdgeLocator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
message QueryRoutesResponse {
|
message QueryRoutesResponse {
|
||||||
|
/**
|
||||||
|
The route that results from the path finding operation. This is still a
|
||||||
|
repeated field to retain backwards compatibility.
|
||||||
|
*/
|
||||||
repeated Route routes = 1 [json_name = "routes"];
|
repeated Route routes = 1 [json_name = "routes"];
|
||||||
|
|
||||||
|
/**
|
||||||
|
The success probability of the returned route based on the current mission
|
||||||
|
control state. [EXPERIMENTAL]
|
||||||
|
*/
|
||||||
|
double success_prob = 2 [json_name = "success_prob"];
|
||||||
}
|
}
|
||||||
|
|
||||||
message Hop {
|
message Hop {
|
||||||
@ -1663,7 +1817,7 @@ message Hop {
|
|||||||
height, the next 3 the index within the block, and the last 2 bytes are the
|
height, the next 3 the index within the block, and the last 2 bytes are the
|
||||||
output index for the channel.
|
output index for the channel.
|
||||||
*/
|
*/
|
||||||
uint64 chan_id = 1 [json_name = "chan_id"];
|
uint64 chan_id = 1 [json_name = "chan_id", jstype = JS_STRING];
|
||||||
int64 chan_capacity = 2 [json_name = "chan_capacity"];
|
int64 chan_capacity = 2 [json_name = "chan_capacity"];
|
||||||
int64 amt_to_forward = 3 [json_name = "amt_to_forward", deprecated = true];
|
int64 amt_to_forward = 3 [json_name = "amt_to_forward", deprecated = true];
|
||||||
int64 fee = 4 [json_name = "fee", deprecated = true];
|
int64 fee = 4 [json_name = "fee", deprecated = true];
|
||||||
@ -1676,6 +1830,12 @@ message Hop {
|
|||||||
can be executed without relying on a copy of the channel graph.
|
can be executed without relying on a copy of the channel graph.
|
||||||
*/
|
*/
|
||||||
string pub_key = 8 [json_name = "pub_key"];
|
string pub_key = 8 [json_name = "pub_key"];
|
||||||
|
|
||||||
|
/**
|
||||||
|
If set to true, then this hop will be encoded using the new variable length
|
||||||
|
TLV format.
|
||||||
|
*/
|
||||||
|
bool tlv_payload = 9 [json_name = "tlv_payload"];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1698,7 +1858,7 @@ message Route {
|
|||||||
/**
|
/**
|
||||||
The sum of the fees paid at each hop within the final route. In the case
|
The sum of the fees paid at each hop within the final route. In the case
|
||||||
of a one-hop payment, this value will be zero as we don't need to pay a fee
|
of a one-hop payment, this value will be zero as we don't need to pay a fee
|
||||||
it ourself.
|
to ourselves.
|
||||||
*/
|
*/
|
||||||
int64 total_fees = 2 [json_name = "total_fees", deprecated = true];
|
int64 total_fees = 2 [json_name = "total_fees", deprecated = true];
|
||||||
|
|
||||||
@ -1730,6 +1890,9 @@ message Route {
|
|||||||
message NodeInfoRequest {
|
message NodeInfoRequest {
|
||||||
/// The 33-byte hex-encoded compressed public of the target node
|
/// The 33-byte hex-encoded compressed public of the target node
|
||||||
string pub_key = 1;
|
string pub_key = 1;
|
||||||
|
|
||||||
|
/// If true, will include all known channels associated with the node.
|
||||||
|
bool include_channels = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message NodeInfo {
|
message NodeInfo {
|
||||||
@ -1742,8 +1905,14 @@ message NodeInfo {
|
|||||||
*/
|
*/
|
||||||
LightningNode node = 1 [json_name = "node"];
|
LightningNode node = 1 [json_name = "node"];
|
||||||
|
|
||||||
|
/// The total number of channels for the node.
|
||||||
uint32 num_channels = 2 [json_name = "num_channels"];
|
uint32 num_channels = 2 [json_name = "num_channels"];
|
||||||
|
|
||||||
|
/// The sum of all channels capacity for the node, denominated in satoshis.
|
||||||
int64 total_capacity = 3 [json_name = "total_capacity"];
|
int64 total_capacity = 3 [json_name = "total_capacity"];
|
||||||
|
|
||||||
|
/// A list of all public channels for the node.
|
||||||
|
repeated ChannelEdge channels = 4 [json_name = "channels"];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1772,6 +1941,7 @@ message RoutingPolicy {
|
|||||||
int64 fee_rate_milli_msat = 4 [json_name = "fee_rate_milli_msat"];
|
int64 fee_rate_milli_msat = 4 [json_name = "fee_rate_milli_msat"];
|
||||||
bool disabled = 5 [json_name = "disabled"];
|
bool disabled = 5 [json_name = "disabled"];
|
||||||
uint64 max_htlc_msat = 6 [json_name = "max_htlc_msat"];
|
uint64 max_htlc_msat = 6 [json_name = "max_htlc_msat"];
|
||||||
|
uint32 last_update = 7 [json_name = "last_update"];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1788,10 +1958,10 @@ message ChannelEdge {
|
|||||||
height, the next 3 the index within the block, and the last 2 bytes are the
|
height, the next 3 the index within the block, and the last 2 bytes are the
|
||||||
output index for the channel.
|
output index for the channel.
|
||||||
*/
|
*/
|
||||||
uint64 channel_id = 1 [json_name = "channel_id"];
|
uint64 channel_id = 1 [json_name = "channel_id", jstype = JS_STRING];
|
||||||
string chan_point = 2 [json_name = "chan_point"];
|
string chan_point = 2 [json_name = "chan_point"];
|
||||||
|
|
||||||
uint32 last_update = 3 [json_name = "last_update"];
|
uint32 last_update = 3 [json_name = "last_update", deprecated = true];
|
||||||
|
|
||||||
string node1_pub = 4 [json_name = "node1_pub"];
|
string node1_pub = 4 [json_name = "node1_pub"];
|
||||||
string node2_pub = 5 [json_name = "node2_pub"];
|
string node2_pub = 5 [json_name = "node2_pub"];
|
||||||
@ -1826,7 +1996,7 @@ message ChanInfoRequest {
|
|||||||
height, the next 3 the index within the block, and the last 2 bytes are the
|
height, the next 3 the index within the block, and the last 2 bytes are the
|
||||||
output index for the channel.
|
output index for the channel.
|
||||||
*/
|
*/
|
||||||
uint64 chan_id = 1;
|
uint64 chan_id = 1 [jstype = JS_STRING];
|
||||||
}
|
}
|
||||||
|
|
||||||
message NetworkInfoRequest {
|
message NetworkInfoRequest {
|
||||||
@ -1846,6 +2016,9 @@ message NetworkInfo {
|
|||||||
int64 max_channel_size = 9 [json_name = "max_channel_size"];
|
int64 max_channel_size = 9 [json_name = "max_channel_size"];
|
||||||
int64 median_channel_size_sat = 10 [json_name = "median_channel_size_sat"];
|
int64 median_channel_size_sat = 10 [json_name = "median_channel_size_sat"];
|
||||||
|
|
||||||
|
// The number of edges marked as zombies.
|
||||||
|
uint64 num_zombie_chans = 11 [json_name = "num_zombie_chans"];
|
||||||
|
|
||||||
// TODO(roasbeef): fee rate info, expiry
|
// TODO(roasbeef): fee rate info, expiry
|
||||||
// * also additional RPC for tracking fee info once in
|
// * also additional RPC for tracking fee info once in
|
||||||
}
|
}
|
||||||
@ -1864,6 +2037,7 @@ message NodeUpdate {
|
|||||||
string identity_key = 2;
|
string identity_key = 2;
|
||||||
bytes global_features = 3;
|
bytes global_features = 3;
|
||||||
string alias = 4;
|
string alias = 4;
|
||||||
|
string color = 5;
|
||||||
}
|
}
|
||||||
message ChannelEdgeUpdate {
|
message ChannelEdgeUpdate {
|
||||||
/**
|
/**
|
||||||
@ -1871,7 +2045,7 @@ message ChannelEdgeUpdate {
|
|||||||
height, the next 3 the index within the block, and the last 2 bytes are the
|
height, the next 3 the index within the block, and the last 2 bytes are the
|
||||||
output index for the channel.
|
output index for the channel.
|
||||||
*/
|
*/
|
||||||
uint64 chan_id = 1;
|
uint64 chan_id = 1 [jstype = JS_STRING];
|
||||||
|
|
||||||
ChannelPoint chan_point = 2;
|
ChannelPoint chan_point = 2;
|
||||||
|
|
||||||
@ -1888,7 +2062,7 @@ message ClosedChannelUpdate {
|
|||||||
height, the next 3 the index within the block, and the last 2 bytes are the
|
height, the next 3 the index within the block, and the last 2 bytes are the
|
||||||
output index for the channel.
|
output index for the channel.
|
||||||
*/
|
*/
|
||||||
uint64 chan_id = 1;
|
uint64 chan_id = 1 [jstype = JS_STRING];
|
||||||
int64 capacity = 2;
|
int64 capacity = 2;
|
||||||
uint32 closed_height = 3;
|
uint32 closed_height = 3;
|
||||||
ChannelPoint chan_point = 4;
|
ChannelPoint chan_point = 4;
|
||||||
@ -1899,7 +2073,7 @@ message HopHint {
|
|||||||
string node_id = 1 [json_name = "node_id"];
|
string node_id = 1 [json_name = "node_id"];
|
||||||
|
|
||||||
/// The unique identifier of the channel.
|
/// The unique identifier of the channel.
|
||||||
uint64 chan_id = 2 [json_name = "chan_id"];
|
uint64 chan_id = 2 [json_name = "chan_id", jstype = JS_STRING];
|
||||||
|
|
||||||
/// The base fee of the channel denominated in millisatoshis.
|
/// The base fee of the channel denominated in millisatoshis.
|
||||||
uint32 fee_base_msat = 3 [json_name = "fee_base_msat"];
|
uint32 fee_base_msat = 3 [json_name = "fee_base_msat"];
|
||||||
@ -2039,6 +2213,42 @@ message Invoice {
|
|||||||
The state the invoice is in.
|
The state the invoice is in.
|
||||||
*/
|
*/
|
||||||
InvoiceState state = 21 [json_name = "state"];
|
InvoiceState state = 21 [json_name = "state"];
|
||||||
|
|
||||||
|
/// List of HTLCs paying to this invoice [EXPERIMENTAL].
|
||||||
|
repeated InvoiceHTLC htlcs = 22 [json_name = "htlcs"];
|
||||||
|
}
|
||||||
|
|
||||||
|
enum InvoiceHTLCState {
|
||||||
|
ACCEPTED = 0;
|
||||||
|
SETTLED = 1;
|
||||||
|
CANCELED = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Details of an HTLC that paid to an invoice
|
||||||
|
message InvoiceHTLC {
|
||||||
|
/// Short channel id over which the htlc was received.
|
||||||
|
uint64 chan_id = 1 [json_name = "chan_id", jstype = JS_STRING];
|
||||||
|
|
||||||
|
/// Index identifying the htlc on the channel.
|
||||||
|
uint64 htlc_index = 2 [json_name = "htlc_index"];
|
||||||
|
|
||||||
|
/// The amount of the htlc in msat.
|
||||||
|
uint64 amt_msat = 3 [json_name = "amt_msat"];
|
||||||
|
|
||||||
|
/// Block height at which this htlc was accepted.
|
||||||
|
int32 accept_height = 4 [json_name = "accept_height"];
|
||||||
|
|
||||||
|
/// Time at which this htlc was accepted.
|
||||||
|
int64 accept_time = 5 [json_name = "accept_time"];
|
||||||
|
|
||||||
|
/// Time at which this htlc was settled or canceled.
|
||||||
|
int64 resolve_time = 6 [json_name = "resolve_time"];
|
||||||
|
|
||||||
|
/// Block height at which this htlc expires.
|
||||||
|
int32 expiry_height = 7 [json_name = "expiry_height"];
|
||||||
|
|
||||||
|
/// Current state the htlc is in.
|
||||||
|
InvoiceHTLCState state = 8 [json_name = "state"];
|
||||||
}
|
}
|
||||||
|
|
||||||
message AddInvoiceResponse {
|
message AddInvoiceResponse {
|
||||||
@ -2141,8 +2351,8 @@ message Payment {
|
|||||||
/// The path this payment took
|
/// The path this payment took
|
||||||
repeated string path = 4 [ json_name = "path" ];
|
repeated string path = 4 [ json_name = "path" ];
|
||||||
|
|
||||||
/// The fee paid for this payment in satoshis
|
/// Deprecated, use fee_sat or fee_msat.
|
||||||
int64 fee = 5 [json_name = "fee"];
|
int64 fee = 5 [json_name = "fee", deprecated = true];
|
||||||
|
|
||||||
/// The payment preimage
|
/// The payment preimage
|
||||||
string payment_preimage = 6 [json_name = "payment_preimage"];
|
string payment_preimage = 6 [json_name = "payment_preimage"];
|
||||||
@ -2152,9 +2362,34 @@ message Payment {
|
|||||||
|
|
||||||
/// The value of the payment in milli-satoshis
|
/// The value of the payment in milli-satoshis
|
||||||
int64 value_msat = 8 [json_name = "value_msat"];
|
int64 value_msat = 8 [json_name = "value_msat"];
|
||||||
|
|
||||||
|
/// The optional payment request being fulfilled.
|
||||||
|
string payment_request = 9 [json_name = "payment_request"];
|
||||||
|
|
||||||
|
enum PaymentStatus {
|
||||||
|
UNKNOWN = 0;
|
||||||
|
IN_FLIGHT = 1;
|
||||||
|
SUCCEEDED = 2;
|
||||||
|
FAILED = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The status of the payment.
|
||||||
|
PaymentStatus status = 10 [json_name = "status"];
|
||||||
|
|
||||||
|
/// The fee paid for this payment in satoshis
|
||||||
|
int64 fee_sat = 11 [json_name = "fee_sat"];
|
||||||
|
|
||||||
|
/// The fee paid for this payment in milli-satoshis
|
||||||
|
int64 fee_msat = 12 [json_name = "fee_msat"];
|
||||||
}
|
}
|
||||||
|
|
||||||
message ListPaymentsRequest {
|
message ListPaymentsRequest {
|
||||||
|
/**
|
||||||
|
If true, then return payments that have not yet fully completed. This means
|
||||||
|
that pending payments, as well as failed payments will show up if this
|
||||||
|
field is set to True.
|
||||||
|
*/
|
||||||
|
bool include_incomplete = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ListPaymentsResponse {
|
message ListPaymentsResponse {
|
||||||
@ -2246,6 +2481,9 @@ message PolicyUpdateRequest {
|
|||||||
|
|
||||||
/// The required timelock delta for HTLCs forwarded over the channel.
|
/// The required timelock delta for HTLCs forwarded over the channel.
|
||||||
uint32 time_lock_delta = 5 [json_name = "time_lock_delta"];
|
uint32 time_lock_delta = 5 [json_name = "time_lock_delta"];
|
||||||
|
|
||||||
|
/// If set, the maximum HTLC size in milli-satoshis. If unset, the maximum HTLC will be unchanged.
|
||||||
|
uint64 max_htlc_msat = 6 [json_name = "max_htlc_msat"];
|
||||||
}
|
}
|
||||||
message PolicyUpdateResponse {
|
message PolicyUpdateResponse {
|
||||||
}
|
}
|
||||||
@ -2268,10 +2506,10 @@ message ForwardingEvent {
|
|||||||
uint64 timestamp = 1 [json_name = "timestamp"];
|
uint64 timestamp = 1 [json_name = "timestamp"];
|
||||||
|
|
||||||
/// The incoming channel ID that carried the HTLC that created the circuit.
|
/// The incoming channel ID that carried the HTLC that created the circuit.
|
||||||
uint64 chan_id_in = 2 [json_name = "chan_id_in"];
|
uint64 chan_id_in = 2 [json_name = "chan_id_in", jstype = JS_STRING];
|
||||||
|
|
||||||
/// The outgoing channel ID that carried the preimage that completed the circuit.
|
/// The outgoing channel ID that carried the preimage that completed the circuit.
|
||||||
uint64 chan_id_out = 4 [json_name = "chan_id_out"];
|
uint64 chan_id_out = 4 [json_name = "chan_id_out", jstype = JS_STRING];
|
||||||
|
|
||||||
/// The total amount (in satoshis) of the incoming HTLC that created half the circuit.
|
/// The total amount (in satoshis) of the incoming HTLC that created half the circuit.
|
||||||
uint64 amt_in = 5 [json_name = "amt_in"];
|
uint64 amt_in = 5 [json_name = "amt_in"];
|
||||||
@ -2285,6 +2523,13 @@ message ForwardingEvent {
|
|||||||
/// The total fee (in milli-satoshis) that this payment circuit carried.
|
/// The total fee (in milli-satoshis) that this payment circuit carried.
|
||||||
uint64 fee_msat = 8 [json_name = "fee_msat"];
|
uint64 fee_msat = 8 [json_name = "fee_msat"];
|
||||||
|
|
||||||
|
/// The total amount (in milli-satoshis) of the incoming HTLC that created half the circuit.
|
||||||
|
uint64 amt_in_msat = 9 [json_name = "amt_in_msat"];
|
||||||
|
|
||||||
|
/// The total amount (in milli-satoshis) of the outgoing HTLC that created the second half of the circuit.
|
||||||
|
uint64 amt_out_msat = 10 [json_name = "amt_out_msat"];
|
||||||
|
|
||||||
|
|
||||||
// TODO(roasbeef): add settlement latency?
|
// TODO(roasbeef): add settlement latency?
|
||||||
// * use FPE on the chan id?
|
// * use FPE on the chan id?
|
||||||
// * also list failures?
|
// * also list failures?
|
||||||
@ -2298,7 +2543,7 @@ message ForwardingHistoryResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
message ExportChannelBackupRequest {
|
message ExportChannelBackupRequest {
|
||||||
/// The target chanenl point to obtain a back up for.
|
/// The target channel point to obtain a back up for.
|
||||||
ChannelPoint chan_point = 1;
|
ChannelPoint chan_point = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2310,7 +2555,7 @@ message ChannelBackup {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
Is an encrypted single-chan backup. this can be passed to
|
Is an encrypted single-chan backup. this can be passed to
|
||||||
RestoreChannelBackups, or the WalletUnlocker Innit and Unlock methods in
|
RestoreChannelBackups, or the WalletUnlocker Init and Unlock methods in
|
||||||
order to trigger the recovery protocol.
|
order to trigger the recovery protocol.
|
||||||
*/
|
*/
|
||||||
bytes chan_backup = 2 [ json_name = "chan_backup" ];
|
bytes chan_backup = 2 [ json_name = "chan_backup" ];
|
||||||
@ -2365,3 +2610,19 @@ message ChannelBackupSubscription {}
|
|||||||
|
|
||||||
message VerifyChanBackupResponse {
|
message VerifyChanBackupResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message MacaroonPermission {
|
||||||
|
/// The entity a permission grants access to.
|
||||||
|
string entity = 1 [json_name = "entity"];
|
||||||
|
|
||||||
|
/// The action that is granted.
|
||||||
|
string action = 2 [json_name = "action"];
|
||||||
|
}
|
||||||
|
message BakeMacaroonRequest {
|
||||||
|
/// The list of permissions the new macaroon should grant.
|
||||||
|
repeated MacaroonPermission permissions = 1 [json_name = "permissions"];
|
||||||
|
}
|
||||||
|
message BakeMacaroonResponse {
|
||||||
|
/// The hex encoded macaroon, serialized in binary format.
|
||||||
|
string macaroon = 1 [json_name = "macaroon"];
|
||||||
|
}
|
||||||
|
@ -280,6 +280,11 @@ class LightningStub(object):
|
|||||||
request_serializer=rpc__pb2.OpenChannelRequest.SerializeToString,
|
request_serializer=rpc__pb2.OpenChannelRequest.SerializeToString,
|
||||||
response_deserializer=rpc__pb2.OpenStatusUpdate.FromString,
|
response_deserializer=rpc__pb2.OpenStatusUpdate.FromString,
|
||||||
)
|
)
|
||||||
|
self.ChannelAcceptor = channel.stream_stream(
|
||||||
|
'/lnrpc.Lightning/ChannelAcceptor',
|
||||||
|
request_serializer=rpc__pb2.ChannelAcceptResponse.SerializeToString,
|
||||||
|
response_deserializer=rpc__pb2.ChannelAcceptRequest.FromString,
|
||||||
|
)
|
||||||
self.CloseChannel = channel.unary_stream(
|
self.CloseChannel = channel.unary_stream(
|
||||||
'/lnrpc.Lightning/CloseChannel',
|
'/lnrpc.Lightning/CloseChannel',
|
||||||
request_serializer=rpc__pb2.CloseChannelRequest.SerializeToString,
|
request_serializer=rpc__pb2.CloseChannelRequest.SerializeToString,
|
||||||
@ -425,6 +430,11 @@ class LightningStub(object):
|
|||||||
request_serializer=rpc__pb2.ChannelBackupSubscription.SerializeToString,
|
request_serializer=rpc__pb2.ChannelBackupSubscription.SerializeToString,
|
||||||
response_deserializer=rpc__pb2.ChanBackupSnapshot.FromString,
|
response_deserializer=rpc__pb2.ChanBackupSnapshot.FromString,
|
||||||
)
|
)
|
||||||
|
self.BakeMacaroon = channel.unary_unary(
|
||||||
|
'/lnrpc.Lightning/BakeMacaroon',
|
||||||
|
request_serializer=rpc__pb2.BakeMacaroonRequest.SerializeToString,
|
||||||
|
response_deserializer=rpc__pb2.BakeMacaroonResponse.FromString,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class LightningServicer(object):
|
class LightningServicer(object):
|
||||||
@ -435,7 +445,7 @@ class LightningServicer(object):
|
|||||||
"""* lncli: `walletbalance`
|
"""* lncli: `walletbalance`
|
||||||
WalletBalance returns total unspent outputs(confirmed and unconfirmed), all
|
WalletBalance returns total unspent outputs(confirmed and unconfirmed), all
|
||||||
confirmed unspent outputs and all unconfirmed unspent outputs under control
|
confirmed unspent outputs and all unconfirmed unspent outputs under control
|
||||||
of the wallet.
|
of the wallet.
|
||||||
"""
|
"""
|
||||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||||
context.set_details('Method not implemented!')
|
context.set_details('Method not implemented!')
|
||||||
@ -600,7 +610,7 @@ class LightningServicer(object):
|
|||||||
raise NotImplementedError('Method not implemented!')
|
raise NotImplementedError('Method not implemented!')
|
||||||
|
|
||||||
def SubscribeChannelEvents(self, request, context):
|
def SubscribeChannelEvents(self, request, context):
|
||||||
"""* lncli: `subscribechannelevents`
|
"""*
|
||||||
SubscribeChannelEvents creates a uni-directional stream from the server to
|
SubscribeChannelEvents creates a uni-directional stream from the server to
|
||||||
the client in which any updates relevant to the state of the channels are
|
the client in which any updates relevant to the state of the channels are
|
||||||
sent over. Events include new active channels, inactive channels, and closed
|
sent over. Events include new active channels, inactive channels, and closed
|
||||||
@ -612,7 +622,7 @@ class LightningServicer(object):
|
|||||||
|
|
||||||
def ClosedChannels(self, request, context):
|
def ClosedChannels(self, request, context):
|
||||||
"""* lncli: `closedchannels`
|
"""* lncli: `closedchannels`
|
||||||
ClosedChannels returns a description of all the closed channels that
|
ClosedChannels returns a description of all the closed channels that
|
||||||
this node was a participant in.
|
this node was a participant in.
|
||||||
"""
|
"""
|
||||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||||
@ -642,6 +652,18 @@ class LightningServicer(object):
|
|||||||
context.set_details('Method not implemented!')
|
context.set_details('Method not implemented!')
|
||||||
raise NotImplementedError('Method not implemented!')
|
raise NotImplementedError('Method not implemented!')
|
||||||
|
|
||||||
|
def ChannelAcceptor(self, request_iterator, context):
|
||||||
|
"""*
|
||||||
|
ChannelAcceptor dispatches a bi-directional streaming RPC in which
|
||||||
|
OpenChannel requests are sent to the client and the client responds with
|
||||||
|
a boolean that tells LND whether or not to accept the channel. This allows
|
||||||
|
node operators to specify their own criteria for accepting inbound channels
|
||||||
|
through a single persistent connection.
|
||||||
|
"""
|
||||||
|
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||||
|
context.set_details('Method not implemented!')
|
||||||
|
raise NotImplementedError('Method not implemented!')
|
||||||
|
|
||||||
def CloseChannel(self, request, context):
|
def CloseChannel(self, request, context):
|
||||||
"""* lncli: `closechannel`
|
"""* lncli: `closechannel`
|
||||||
CloseChannel attempts to close an active channel identified by its channel
|
CloseChannel attempts to close an active channel identified by its channel
|
||||||
@ -822,7 +844,7 @@ class LightningServicer(object):
|
|||||||
"""* lncli: `queryroutes`
|
"""* lncli: `queryroutes`
|
||||||
QueryRoutes attempts to query the daemon's Channel Router for a possible
|
QueryRoutes attempts to query the daemon's Channel Router for a possible
|
||||||
route to a target destination capable of carrying a specific amount of
|
route to a target destination capable of carrying a specific amount of
|
||||||
satoshis. The retuned route contains the full details required to craft and
|
satoshis. The returned route contains the full details required to craft and
|
||||||
send an HTLC, also including the necessary information that should be
|
send an HTLC, also including the necessary information that should be
|
||||||
present within the Sphinx packet encapsulated within the HTLC.
|
present within the Sphinx packet encapsulated within the HTLC.
|
||||||
"""
|
"""
|
||||||
@ -967,6 +989,16 @@ class LightningServicer(object):
|
|||||||
context.set_details('Method not implemented!')
|
context.set_details('Method not implemented!')
|
||||||
raise NotImplementedError('Method not implemented!')
|
raise NotImplementedError('Method not implemented!')
|
||||||
|
|
||||||
|
def BakeMacaroon(self, request, context):
|
||||||
|
"""* lncli: `bakemacaroon`
|
||||||
|
BakeMacaroon allows the creation of a new macaroon with custom read and
|
||||||
|
write permissions. No first-party caveats are added since this can be done
|
||||||
|
offline.
|
||||||
|
"""
|
||||||
|
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||||
|
context.set_details('Method not implemented!')
|
||||||
|
raise NotImplementedError('Method not implemented!')
|
||||||
|
|
||||||
|
|
||||||
def add_LightningServicer_to_server(servicer, server):
|
def add_LightningServicer_to_server(servicer, server):
|
||||||
rpc_method_handlers = {
|
rpc_method_handlers = {
|
||||||
@ -1075,6 +1107,11 @@ def add_LightningServicer_to_server(servicer, server):
|
|||||||
request_deserializer=rpc__pb2.OpenChannelRequest.FromString,
|
request_deserializer=rpc__pb2.OpenChannelRequest.FromString,
|
||||||
response_serializer=rpc__pb2.OpenStatusUpdate.SerializeToString,
|
response_serializer=rpc__pb2.OpenStatusUpdate.SerializeToString,
|
||||||
),
|
),
|
||||||
|
'ChannelAcceptor': grpc.stream_stream_rpc_method_handler(
|
||||||
|
servicer.ChannelAcceptor,
|
||||||
|
request_deserializer=rpc__pb2.ChannelAcceptResponse.FromString,
|
||||||
|
response_serializer=rpc__pb2.ChannelAcceptRequest.SerializeToString,
|
||||||
|
),
|
||||||
'CloseChannel': grpc.unary_stream_rpc_method_handler(
|
'CloseChannel': grpc.unary_stream_rpc_method_handler(
|
||||||
servicer.CloseChannel,
|
servicer.CloseChannel,
|
||||||
request_deserializer=rpc__pb2.CloseChannelRequest.FromString,
|
request_deserializer=rpc__pb2.CloseChannelRequest.FromString,
|
||||||
@ -1220,6 +1257,11 @@ def add_LightningServicer_to_server(servicer, server):
|
|||||||
request_deserializer=rpc__pb2.ChannelBackupSubscription.FromString,
|
request_deserializer=rpc__pb2.ChannelBackupSubscription.FromString,
|
||||||
response_serializer=rpc__pb2.ChanBackupSnapshot.SerializeToString,
|
response_serializer=rpc__pb2.ChanBackupSnapshot.SerializeToString,
|
||||||
),
|
),
|
||||||
|
'BakeMacaroon': grpc.unary_unary_rpc_method_handler(
|
||||||
|
servicer.BakeMacaroon,
|
||||||
|
request_deserializer=rpc__pb2.BakeMacaroonRequest.FromString,
|
||||||
|
response_serializer=rpc__pb2.BakeMacaroonResponse.SerializeToString,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
generic_handler = grpc.method_handlers_generic_handler(
|
generic_handler = grpc.method_handlers_generic_handler(
|
||||||
'lnrpc.Lightning', rpc_method_handlers)
|
'lnrpc.Lightning', rpc_method_handlers)
|
||||||
|