diff --git a/socket_py/credentials.py b/socket_py/credentials.py
new file mode 100644
index 0000000..63d6f7f
--- /dev/null
+++ b/socket_py/credentials.py
@@ -0,0 +1,3 @@
+nodeAddr = "Address of node"
+privateKey = "Ethereum private key"
+address = "Ethereum address belonging to private key"
\ No newline at end of file
diff --git a/socket_py/qt/Socket_python.pro b/socket_py/qt/Socket_python.pro
new file mode 100644
index 0000000..7dfd315
--- /dev/null
+++ b/socket_py/qt/Socket_python.pro
@@ -0,0 +1,40 @@
+#-------------------------------------------------
+#
+# Project created by QtCreator 2019-08-20T08:38:25
+#
+#-------------------------------------------------
+
+QT += core gui
+
+greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
+
+TARGET = Socket_python
+TEMPLATE = app
+
+# The following define makes your compiler emit warnings if you use
+# any feature of Qt which has been marked as deprecated (the exact warnings
+# depend on your compiler). Please consult the documentation of the
+# deprecated API in order to know how to port your code away from it.
+DEFINES += QT_DEPRECATED_WARNINGS
+
+# You can also make your code fail to compile if you use deprecated APIs.
+# In order to do so, uncomment the following line.
+# You can also select to disable deprecated APIs only up to a certain version of Qt.
+#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
+
+CONFIG += c++11
+
+SOURCES += \
+ main.cpp \
+ mainwindow.cpp
+
+HEADERS += \
+ mainwindow.h
+
+FORMS += \
+ mainwindow.ui
+
+# Default rules for deployment.
+qnx: target.path = /tmp/$${TARGET}/bin
+else: unix:!android: target.path = /opt/$${TARGET}/bin
+!isEmpty(target.path): INSTALLS += target
diff --git a/socket_py/qt/Socket_python.pro.user b/socket_py/qt/Socket_python.pro.user
new file mode 100644
index 0000000..02a9aa3
--- /dev/null
+++ b/socket_py/qt/Socket_python.pro.user
@@ -0,0 +1,336 @@
+
+
+
+
+
+ EnvironmentId
+ {92870ea4-37a7-43bd-990a-109b15ee3aaf}
+
+
+ ProjectExplorer.Project.ActiveTarget
+ 0
+
+
+ ProjectExplorer.Project.EditorSettings
+
+ true
+ false
+ true
+
+ Cpp
+
+ CppGlobal
+
+
+
+ QmlJS
+
+ QmlJSGlobal
+
+
+ 2
+ UTF-8
+ false
+ 4
+ false
+ 80
+ true
+ true
+ 1
+ true
+ false
+ 0
+ true
+ true
+ 0
+ 8
+ true
+ 1
+ true
+ true
+ true
+ false
+
+
+
+ ProjectExplorer.Project.SocketinSettings
+
+
+ true
+
+
+
+ ProjectExplorer.Project.Target.0
+
+ Desktop Qt 5.13.0 clang 64bit
+ Desktop Qt 5.13.0 clang 64bit
+ qt.qt5.5130.clang_64_kit
+ 0
+ 0
+ 0
+
+ /Users/Daniel/Documents/Uni/Bachelor/Absolviert/Bachelorarbeit/git/Socket_py/build-Socket_python-Desktop_Qt_5_13_0_clang_64bit-Debug
+
+
+ true
+ qmake
+
+ QtProjectManager.QMakeBuildStep
+ true
+
+ false
+ false
+ false
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ false
+
+
+ false
+
+ 2
+ Erstellen
+
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ true
+ clean
+
+ false
+
+ 1
+ Bereinigen
+
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ Debug
+ Debug
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 2
+ true
+
+
+ /Users/Daniel/Documents/Uni/Bachelor/Absolviert/Bachelorarbeit/git/Socket_py/build-Socket_python-Desktop_Qt_5_13_0_clang_64bit-Release
+
+
+ true
+ qmake
+
+ QtProjectManager.QMakeBuildStep
+ false
+
+ false
+ false
+ true
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ false
+
+
+ false
+
+ 2
+ Erstellen
+
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ true
+ clean
+
+ false
+
+ 1
+ Bereinigen
+
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ Release
+ Release
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 0
+ true
+
+
+ /Users/Daniel/Documents/Uni/Bachelor/Absolviert/Bachelorarbeit/git/Socket_py/build-Socket_python-Desktop_Qt_5_13_0_clang_64bit-Profile
+
+
+ true
+ qmake
+
+ QtProjectManager.QMakeBuildStep
+ true
+
+ false
+ true
+ true
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ false
+
+
+ false
+
+ 2
+ Erstellen
+
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ true
+ clean
+
+ false
+
+ 1
+ Bereinigen
+
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ Profile
+ Profile
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 0
+ true
+
+ 3
+
+
+ 0
+ Deployment
+
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+ Deployment-Konfiguration
+
+ ProjectExplorer.DefaultDeployConfiguration
+
+ 1
+
+
+ dwarf
+
+ cpu-cycles
+
+
+ 250
+ -F
+ true
+ 4096
+ false
+ false
+ 1000
+
+ true
+
+ false
+ false
+ false
+ false
+ true
+ 0.01
+ 10
+ true
+ kcachegrind
+ 1
+ 25
+
+ 1
+ true
+ false
+ true
+ valgrind
+
+ 0
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 10
+ 11
+ 12
+ 13
+ 14
+
+ 2
+
+ Socket_python
+
+ Qt4ProjectManager.Qt4RunConfiguration:/Users/Daniel/Documents/Uni/Bachelor/Absolviert/Bachelorarbeit/git/Socket_py/qt/Socket_python.pro
+
+ 3768
+ false
+ true
+ false
+ true
+ false
+ false
+ true
+
+ /Users/Daniel/Documents/Uni/Bachelor/Absolviert/Bachelorarbeit/git/Socket_py/build-Socket_python-Desktop_Qt_5_13_0_clang_64bit-Debug/Socket_python.app/Contents/MacOS
+
+ 1
+
+
+
+ ProjectExplorer.Project.TargetCount
+ 1
+
+
+ ProjectExplorer.Project.Updater.FileVersion
+ 21
+
+
+ Version
+ 21
+
+
diff --git a/socket_py/qt/main.cpp b/socket_py/qt/main.cpp
new file mode 100644
index 0000000..b48f94e
--- /dev/null
+++ b/socket_py/qt/main.cpp
@@ -0,0 +1,11 @@
+#include "mainwindow.h"
+#include
+
+int main(int argc, char *argv[])
+{
+ QApplication a(argc, argv);
+ MainWindow w;
+ w.show();
+
+ return a.exec();
+}
diff --git a/socket_py/qt/mainwindow.cpp b/socket_py/qt/mainwindow.cpp
new file mode 100644
index 0000000..49d64fc
--- /dev/null
+++ b/socket_py/qt/mainwindow.cpp
@@ -0,0 +1,14 @@
+#include "mainwindow.h"
+#include "ui_mainwindow.h"
+
+MainWindow::MainWindow(QWidget *parent) :
+ QMainWindow(parent),
+ ui(new Ui::MainWindow)
+{
+ ui->setupUi(this);
+}
+
+MainWindow::~MainWindow()
+{
+ delete ui;
+}
diff --git a/socket_py/qt/mainwindow.h b/socket_py/qt/mainwindow.h
new file mode 100644
index 0000000..9353441
--- /dev/null
+++ b/socket_py/qt/mainwindow.h
@@ -0,0 +1,22 @@
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include
+
+namespace Ui {
+class MainWindow;
+}
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ explicit MainWindow(QWidget *parent = nullptr);
+ ~MainWindow();
+
+private:
+ Ui::MainWindow *ui;
+};
+
+#endif // MAINWINDOW_H
diff --git a/socket_py/qt/mainwindow.ui b/socket_py/qt/mainwindow.ui
new file mode 100644
index 0000000..b372619
--- /dev/null
+++ b/socket_py/qt/mainwindow.ui
@@ -0,0 +1,79 @@
+
+
+ MainWindow
+
+
+
+ 0
+ 0
+ 800
+ 480
+
+
+
+ MainWindow
+
+
+ background-color: rgb(50, 50, 50);
+
+
+
+
+
+ 435
+ 439
+ 351
+ 31
+
+
+
+ color: white; font-size:18px
+
+
+ Currently not connected to node
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+
+
+ 720
+ 10
+ 64
+ 64
+
+
+
+ color: transparent; border: none
+
+
+ X
+
+
+
+
+
+ 85
+ 20
+ 630
+ 90
+
+
+
+ color:white; font-size:36px
+
+
+ <html><head/><body><p><span style=" font-size:40pt; font-weight:600; font-style:italic;">Blockchain Smart Outlet</span></p></body></html>
+
+
+ Qt::AlignCenter
+
+
+
+
+
+
+
+
diff --git a/socket_py/socket.py b/socket_py/socket.py
new file mode 100644
index 0000000..bad10fd
--- /dev/null
+++ b/socket_py/socket.py
@@ -0,0 +1,175 @@
+# ui libraries
+from PyQt5.QtGui import QPalette, QFont
+from PyQt5.QtCore import QThread, QObject, pyqtSignal, pyqtSlot, Qt, QEvent, QSize
+from PyQt5.QtWidgets import QApplication, QMainWindow, QScrollerProperties, QScroller, QListWidgetItem
+
+# ethereum library
+from eth_account.messages import encode_defunct
+from web3.middleware import geth_poa_middleware
+from web3.exceptions import TransactionNotFound
+from web3 import Web3
+from ui_mainwindow import Ui_MainWindow
+
+# websockets
+import websockets
+import asyncio
+from socket import socket, AF_INET, SOCK_DGRAM
+
+# utility libraries
+import operator
+import sys
+from enum import Enum
+import json
+from json import JSONDecodeError
+import credentials
+
+DEBUG = False
+
+# credentials
+nodeAddr = credentials.nodeAddr
+contract_abi = '[{"constant":false,"inputs":[{"name":"_newPrice","type":"uint256"}],"name":"changePrice","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_value","type":"uint256"},{"name":"_signature","type":"bytes"}],"name":"closeChannel","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"initializePaymentChannel","outputs":[{"name":"","type":"bool"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[],"name":"timeOutChannel","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"withdraw","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_pricePerSecond","type":"uint256"},{"name":"_expirationDuration","type":"uint256"},{"name":"_minDeposit","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"customer","type":"address"},{"indexed":true,"name":"start","type":"uint256"},{"indexed":true,"name":"maxValue","type":"uint256"},{"indexed":false,"name":"end","type":"uint256"}],"name":"InitializedPaymentChannel","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"},{"indexed":true,"name":"value","type":"uint256"},{"indexed":true,"name":"expired","type":"bool"},{"indexed":false,"name":"duration","type":"uint256"}],"name":"ClosedPaymentChannel","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"oldPrice","type":"uint256"},{"indexed":true,"name":"newPrice","type":"uint256"}],"name":"PriceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"},{"indexed":true,"name":"amount","type":"uint256"}],"name":"Withdrawal","type":"event"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balances","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"channelActive","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"channelCustomer","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"channelExpired","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"creationTimeStamp","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"customerNonces","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"expirationDate","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"expirationDuration","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"maxValue","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"minDeposit","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"pricePerSecond","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_value","type":"uint256"},{"name":"_signature","type":"bytes"}],"name":"verifySignature","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"}]'
+
+etherPriceEUR = 300
+web3 = Web3(Web3.HTTPProvider(nodeAddr))
+# inject the poa compatibility middleware to the innermost layer
+web3.middleware_onion.inject(geth_poa_middleware, layer=0)
+
+privateKey = bytes.fromhex(credentials.privateKey)
+address = web3.toChecksumAddress(credentials.address)
+
+# global thread and ui variables
+window = None
+app = None
+
+
+class State(Enum):
+ disconnected = 0
+ connected_P = 1
+ connected_S = 2
+ initialized_P = 3
+ initialized_S = 4
+ active_P = 5
+ active_S = 6
+ closed = 7
+
+
+# Main window class
+class MainWindow(QMainWindow):
+ def __init__(self, parent=None):
+ super(MainWindow, self).__init__(parent)
+
+ # load ui file
+ self.ui = Ui_MainWindow()
+ self.ui.setupUi(self)
+
+ # start main thread
+ self.node_thread = Node()
+ self.node_thread.start()
+
+ # connect button handlers
+ self.ui.closeButton.clicked.connect(self.close)
+
+ def closeEvent(self, event):
+ # cleanup and end threads
+ try:
+ self.node_thread.threadActive = False
+ self.node_thread.wait()
+ except:
+ pass
+ try:
+ self.ws_thread.threadActive = False
+ self.ws_thread.wait()
+ except:
+ pass
+ # GPIO.cleanup()
+ event.accept() # let the window close
+
+ def terminateThread(self, process):
+ try:
+ thread = operator.attrgetter(process)(self)
+ if thread.threadActive:
+ thread.threadActive = False
+ thread.quit()
+ if (thread.wait(1000) == False):
+ thread.terminate()
+ thread.wait()
+ except AttributeError:
+ # thread was not created yet
+ pass
+
+ def connectWS(self):
+ self.updateInfoCenter('')
+ self.updateInfo('Searching for smart sockets...')
+
+ # start websocket
+ self.ws_thread = WSConnection()
+ self.ws_thread.start()
+
+
+# ethereum node functionality
+class Node(QThread):
+ def __init__(self, parent=window):
+ super(Node, self).__init__(parent)
+ global window
+ self.threadActive = False
+
+ if web3.isConnected():
+ self.threadActive = True
+ else:
+ window.ui.nodeInfoLabel.setText("Not connected to Node")
+
+ def run(self):
+ global window
+ i = 0
+ while self.threadActive:
+ i += 1
+ # check if node is up to date once per second
+ syncing = web3.eth.syncing
+ if syncing is False:
+ blockNumber = web3.eth.blockNumber
+ # TODO remove str(i)
+ window.ui.nodeInfoLabel.setText(
+ "Blocknumber: " + str(blockNumber)
+ )
+
+ else:
+ window.ui.nodeInfoLabel.setText(
+ "Syncing: " + str(syncing.currentBlock) +
+ "/" + str(syncing.highestBlock)
+ )
+
+ QThread().sleep(5)
+
+
+# websocket thread
+class WSConnection(QThread):
+ def __init__(self, parent=window):
+ super(WSConnection, self).__init__(parent)
+ self.threadActive = False
+
+ def run(self):
+ pass
+
+
+def main():
+ global window
+ global app
+
+ # start window and ui
+ app = QApplication(sys.argv)
+ window = MainWindow()
+
+ # show ui
+ # window.showFullScreen()
+ if DEBUG:
+ window.show()
+ else:
+ # show app in fullscreen and hide cursor on RPi
+ window.showFullScreen()
+ app.setOverrideCursor(Qt.BlankCursor)
+
+ sys.exit(app.exec_())
+
+
+if __name__ == "__main__":
+ main()
diff --git a/socket_py/ui_mainwindow.py b/socket_py/ui_mainwindow.py
new file mode 100644
index 0000000..96f6204
--- /dev/null
+++ b/socket_py/ui_mainwindow.py
@@ -0,0 +1,44 @@
+# -*- coding: utf-8 -*-
+
+# Form implementation generated from reading ui file 'qt/mainwindow.ui',
+# licensing of 'qt/mainwindow.ui' applies.
+#
+# Created: Mon Nov 4 22:01:21 2019
+# by: pyside2-uic running on PySide2 5.13.1
+#
+# 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(800, 480)
+ MainWindow.setStyleSheet("background-color: rgb(50, 50, 50);")
+ self.centralWidget = QtWidgets.QWidget(MainWindow)
+ self.centralWidget.setObjectName("centralWidget")
+ self.nodeInfoLabel = QtWidgets.QLabel(self.centralWidget)
+ self.nodeInfoLabel.setGeometry(QtCore.QRect(435, 439, 351, 31))
+ self.nodeInfoLabel.setStyleSheet("color: white; font-size:18px")
+ self.nodeInfoLabel.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
+ self.nodeInfoLabel.setObjectName("nodeInfoLabel")
+ self.closeButton = QtWidgets.QPushButton(self.centralWidget)
+ self.closeButton.setGeometry(QtCore.QRect(720, 10, 64, 64))
+ self.closeButton.setStyleSheet("color: transparent; border: none")
+ self.closeButton.setObjectName("closeButton")
+ self.infoLabel = QtWidgets.QLabel(self.centralWidget)
+ self.infoLabel.setGeometry(QtCore.QRect(85, 20, 630, 90))
+ self.infoLabel.setStyleSheet("color:white; font-size:36px")
+ self.infoLabel.setAlignment(QtCore.Qt.AlignCenter)
+ self.infoLabel.setObjectName("infoLabel")
+ MainWindow.setCentralWidget(self.centralWidget)
+
+ self.retranslateUi(MainWindow)
+ QtCore.QMetaObject.connectSlotsByName(MainWindow)
+
+ def retranslateUi(self, MainWindow):
+ MainWindow.setWindowTitle(QtWidgets.QApplication.translate("MainWindow", "MainWindow", None, -1))
+ self.nodeInfoLabel.setText(QtWidgets.QApplication.translate("MainWindow", "Currently not connected to node", None, -1))
+ self.closeButton.setText(QtWidgets.QApplication.translate("MainWindow", "X", None, -1))
+ self.infoLabel.setText(QtWidgets.QApplication.translate("MainWindow", "Blockchain Smart Outlet
", None, -1))
+