Browse Source

added settings dialog

curiousmuch 7 years ago
parent
commit
1d5d861590
7 changed files with 912 additions and 332 deletions
  1. 37 6
      IdeasXWSCBackend.py
  2. 88 10
      IdeasXWSCView.py
  3. 346 0
      Qt/ideasxdevice.ui.autosave
  4. 197 90
      Qt/mainwindow.ui
  5. 4 4
      icon/svg/icons.svg
  6. 240 0
      mainwindow2.py
  7. 0 222
      wsc_backend.py

+ 37 - 6
IdeasXWSCBackend.py

@@ -45,7 +45,7 @@ except ImportError:
     print("The python classes for IdeasX are missing. Try running the Makefile in" +
             "ideasX-messages.")
 
-from PyQt5.QtCore import QObject, pyqtSignal
+from PyQt5.QtCore import QObject, pyqtSignal, QSettings
     
     
 class IdeasXWSCNetworkThread(QObject): 
@@ -54,6 +54,7 @@ class IdeasXWSCNetworkThread(QObject):
     encoderUpdate = pyqtSignal([dict], name='encoderUpdate')
     networkStatus = pyqtSignal([str], name='networkStatus')
     networkUpdate = pyqtSignal([str], name='networkUpdate')
+    settingsError = pyqtSignal([str], name='settingsError')
     
     def __init__(self, settingFile=None, clientID = None, debug=True, mqttdebug=True):
         super(IdeasXWSCNetworkThread, self).__init__()
@@ -65,6 +66,8 @@ class IdeasXWSCNetworkThread(QObject):
         self.__errorIndex = 0 
         self.__refreshCb = None
         
+        self.__org = 'IdeasX'
+        self.__app = 'Workstation-Client'
         
         # MQTT Topics 
         self.__DEVICETYPE = ["/encoder/+"]
@@ -203,25 +206,44 @@ class IdeasXWSCNetworkThread(QObject):
             self.printError("There was a fucking mistake here.")
             sys.exit(1)
             
-    def guiStartWorkstationClient(self, ip="server.ideasx.tech", port=1883, keepAlive=60):
-        self.ip = ip 
-        self.port = port 
+    def guiStartWorkstationClient(self, ip=None, port=1883, keepAlive=60):
+        
         self.keepAlive = keepAlive
         
+        if ip == None:
+            settings = QSettings(self.__org, self.__app) 
+            settings.beginGroup('Broker')
+            self.ip = settings.value('NetworkBroker', 'ideasx.duckdns.org')
+            self.port = settings.value('NetworkPort', 1883)
+            #self.__LocalBroker = settings.value('LocalBroker', '10.42.0.1')
+            self.__LocalPort = settings.value('LocalPort', 1883)
+            settings.endGroup()
+        else:
+            self.printLine()
+            self.printInfo("Loading hardcoded defaults")
+            self.printLine()
+            self.ip = ip 
+            self.port = port 
+        
         self.printLine()
         self.printInfo("Starting Workstation Client (WSC)")
         self.printLine()
         
         try: 
-            self._mqttc.connect(self.ip, self.port, self.keepAlive)
+            self._mqttc.connect(self.ip, int(self.port), self.keepAlive)
             for device in self.__DEVICETYPE:
                 self._mqttc.subscribe(device + self.__HEALTHTOPIC, 0)
                 self._mqttc.subscribe(device + self.__DATATOPIC, 0)
             self._mqttc.loop_start() # start MQTT Client Thread 
         except: 
             self.printError("There was a fucking mistake here.")
-            sys.exit(1)
+            self.networkStatus.emit("Oh-no! Broker settings are incorrect or there is a network failure")
+#             sys.exit(1)
             
+    def guiRestartWSC(self):
+        self.killWSC()
+        self.networkUpdate.emit("Restarting WSC...")
+        self.guiStartWorkstationClient()
             
     def restartWSC(self):
         self.printInfo("This really doesn't do anything")
@@ -342,6 +364,15 @@ class IdeasXKeyEmulator():
         if encoder not in self.__assignedKeys.keys(): 
             encoder = 'default'
         return self.__assignedKeys[encoder][switch]
+    
+    def getKeyDatabase(self):
+        return self.__assignedKeys 
+    
+    def getDefaultKeyEntry(self):
+        return self.__assignedKeys['default']
+    
+    def setKeyDatabase(self, db):
+        self.__assignedKeys = db
         
     def emulateKey(self, encoder, buttonPayload, deviceType=None):
         '''

+ 88 - 10
IdeasXWSCView.py

@@ -1,3 +1,4 @@
+#!/usr/bin/env python`
 import sys
 import time
 import sip
@@ -248,42 +249,119 @@ class IdeasXEncoder(QtWidgets.QWidget):
     
 
 class IdeasXMainWindow(QtWidgets.QMainWindow):
-    def __init__(self):
+    def __init__(self, wsc):
         super(IdeasXMainWindow, self).__init__()
         self.__ui = Ui_MainWindow()
         self.__ui.setupUi(self)
-
+        self.__wsc = wsc 
+        
         p = self.__ui.contentEncoder.palette()
         p.setColor(self.backgroundRole(), QtCore.Qt.white)
         self.__ui.contentEncoder.setPalette(p)
+        
+        self.__ui.statusMessageWidget = QtWidgets.QLabel()
+        self.__ui.statusMessageWidget.setText("Starting WSC...")
+        self.__ui.statusMessageWidget.setAlignment(QtCore.Qt.AlignLeft)
+        self.__ui.statusbar.addWidget(self.__ui.statusMessageWidget, 1)
+                
+        self.__org = 'IdeasX'
+        self.__app = 'Workstation-Client'
+        
+        self.restoreSettings()
+        
+        self.__ui.buttonSettings.clicked.connect(self.updateBrokerSettings)
+        
+        
+        
 
     def setEncoderLayout(self, layout):
         self.__ui.contentEncoder.setLayout(layout)
         
     def setStatusBarMessage(self, msg):
-        status = QtWidgets.QLabel()
-        status.setText(msg)
-        status.setAlignment(QtCore.Qt.AlignLeft)
-        #status.setAlignment(QtCore.Qt.AlignLeft)
-        self.__ui.statusbar.addWidget(status, 1) # IDK what the 1 does...I need to look it up
+        self.__ui.statusbar.clearMessage()
+        self.__ui.statusMessageWidget.setText(msg)
         
     def setStatusBarUpdate(self, msg):
         self.__ui.statusbar.showMessage(msg)
 
+    def saveSettings(self):
+        '''
+            Saves various backend and front information via Qt's system agnoistic classes. 
+            The following information is saved and restored: 
+            
+            1) MainWindow size and position 
+            2) Switch configuration and assigned keys 
+            3) Encoder Nicknames
+            4) Broker URL and Ports
+        '''
+        # MainWindow Settings
+        settings = QtCore.QSettings(self.__org, self.__app)
+        settings.beginGroup("MainWindow")
+        settings.setValue("size", self.size())
+        settings.setValue("pos", self.pos())
+        settings.endGroup()      
+        
+    def updateBrokerSettings(self):
+        print(self.__ui.networkBroker.text())
+        self.__NetworkBroker = self.__ui.networkBroker.text()
+        self.__LocalBroker = self.__ui.localBroker.text()
+        self.__NetworkPort = int(self.__ui.networkPort.text())
+        self.__LocalPort = int(self.__ui.localPort.text())  
+        
+        settings = QtCore.QSettings(self.__org, self.__app) 
+        settings.beginGroup("Broker")
+        settings.setValue('NetworkBroker', self.__NetworkBroker)
+        settings.setValue('NetworkPort', self.__NetworkPort)
+        settings.setValue('LocalBroker', self.__LocalBroker)
+        settings.setValue('LocalPort', self.__LocalPort)
+        settings.endGroup()
+        self.saveSettings()
+        
+        #self.__ui.statusbar.showMessage("Updated Broker settings. Please Restart the WSC.")
+        self.__wsc.guiRestartWSC()
+        
+    def restoreSettings(self):
+        settings = QtCore.QSettings(self.__org, self.__app)
+        settings.beginGroup("MainWindow")
+        self.resize(settings.value("size", QtCore.QSize(525, 648)))
+        self.move(settings.value("pos", QtCore.QPoint(0, 0)))
+        settings.endGroup()
+        
+        settings.beginGroup("Broker")
+        self.__NetworkBroker = settings.value('NetworkBroker', 'ideasx.duckdns.org')
+        self.__NetworkPort = settings.value('NetworkPort', 1883)
+        self.__LocalBroker = settings.value('LocalBroker', '10.42.0.1')
+        self.__LocalPort = settings.value('LocalPort', 1883)
+        settings.endGroup()
+        
+        self.__ui.networkBroker.setText(self.__NetworkBroker)
+        self.__ui.networkPort.setText(str(self.__NetworkPort))
+        self.__ui.localBroker.setText(self.__LocalBroker)
+        self.__ui.localPort.setText(str(self.__LocalPort))
+        
+        settings.beginGroup('OTAServer')
+        self.__OTAServer = settings.value('OTAServer', 'ideasx.duckdns.org')
+        settings.endGroup()
+        
+    def closeEvent(self, event):
+        self.saveSettings()
+        super(IdeasXMainWindow, self).closeEvent(event)
+        
+        
         
 if __name__ == "__main__":
     app = QtWidgets.QApplication(sys.argv)
     app.setWindowIcon(QtGui.QIcon('icon/logo/ideasx.png'))
-    mainWindow = IdeasXMainWindow()
     wsc = IdeasXWSCNetworkThread()
+    mainWindow = IdeasXMainWindow(wsc)
     encoderManager = IdeasXDeviceManager(IdeasXEncoder, wsc)
     mainWindow.setEncoderLayout(encoderManager.returnLayout())
     
     wsc.encoderUpdate.connect(encoderManager.refreshDevices)
     wsc.networkStatus.connect(mainWindow.setStatusBarMessage)
     wsc.networkUpdate.connect(mainWindow.setStatusBarUpdate)
-    wsc.guiStartWorkstationClient('ideasx.duckdns.org')
-    
+    #wsc.guiStartWorkstationClient('ideasx.duckdns.org')
+    wsc.guiStartWorkstationClient()
     
     
     #timer = QtCore.QTimer()

+ 346 - 0
Qt/ideasxdevice.ui.autosave

@@ -0,0 +1,346 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>IdeasXDevice</class>
+ <widget class="QWidget" name="IdeasXDevice">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>452</width>
+    <height>84</height>
+   </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <property name="minimumSize">
+   <size>
+    <width>452</width>
+    <height>84</height>
+   </size>
+  </property>
+  <property name="maximumSize">
+   <size>
+    <width>16777215</width>
+    <height>84</height>
+   </size>
+  </property>
+  <property name="acceptDrops">
+   <bool>false</bool>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <property name="autoFillBackground">
+   <bool>false</bool>
+  </property>
+  <layout class="QHBoxLayout" name="horizontalLayout">
+   <property name="spacing">
+    <number>0</number>
+   </property>
+   <property name="leftMargin">
+    <number>9</number>
+   </property>
+   <property name="topMargin">
+    <number>3</number>
+   </property>
+   <property name="rightMargin">
+    <number>9</number>
+   </property>
+   <property name="bottomMargin">
+    <number>3</number>
+   </property>
+   <item>
+    <widget class="QWidget" name="widgetInfo" native="true">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Expanding" vsizetype="Ignored">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="minimumSize">
+      <size>
+       <width>290</width>
+       <height>70</height>
+      </size>
+     </property>
+     <widget class="QLabel" name="labelDeviceType">
+      <property name="geometry">
+       <rect>
+        <x>5</x>
+        <y>0</y>
+        <width>101</width>
+        <height>76</height>
+       </rect>
+      </property>
+      <property name="toolTip">
+       <string extracomment="RSSI: -20 dBm"/>
+      </property>
+      <property name="statusTip">
+       <string/>
+      </property>
+      <property name="pixmap">
+       <pixmap>../icon/devicetype/modulev3b.png</pixmap>
+      </property>
+      <property name="scaledContents">
+       <bool>false</bool>
+      </property>
+     </widget>
+     <widget class="QLabel" name="labelModuleID">
+      <property name="geometry">
+       <rect>
+        <x>119</x>
+        <y>5</y>
+        <width>311</width>
+        <height>36</height>
+       </rect>
+      </property>
+      <property name="sizePolicy">
+       <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+        <horstretch>0</horstretch>
+        <verstretch>0</verstretch>
+       </sizepolicy>
+      </property>
+      <property name="font">
+       <font>
+        <family>TakaoPGothic</family>
+        <pointsize>20</pointsize>
+        <weight>50</weight>
+        <italic>false</italic>
+        <bold>false</bold>
+       </font>
+      </property>
+      <property name="frameShape">
+       <enum>QFrame::NoFrame</enum>
+      </property>
+      <property name="text">
+       <string>Sarah Stanton</string>
+      </property>
+      <property name="scaledContents">
+       <bool>true</bool>
+      </property>
+     </widget>
+     <widget class="QLabel" name="labelSignal">
+      <property name="geometry">
+       <rect>
+        <x>117</x>
+        <y>43</y>
+        <width>31</width>
+        <height>31</height>
+       </rect>
+      </property>
+      <property name="toolTip">
+       <string extracomment="-40 dBm"/>
+      </property>
+      <property name="pixmap">
+       <pixmap>../icon/network/network-wireless-signal-ok-symbolic.png</pixmap>
+      </property>
+      <property name="scaledContents">
+       <bool>false</bool>
+      </property>
+     </widget>
+     <widget class="QLabel" name="labelBattery">
+      <property name="geometry">
+       <rect>
+        <x>157</x>
+        <y>43</y>
+        <width>31</width>
+        <height>31</height>
+       </rect>
+      </property>
+      <property name="toolTip">
+       <string extracomment="50%"/>
+      </property>
+      <property name="statusTip">
+       <string extracomment="50%"/>
+      </property>
+      <property name="pixmap">
+       <pixmap>../icon/battery/battery-good-charging-symbolic.png</pixmap>
+      </property>
+      <property name="scaledContents">
+       <bool>false</bool>
+      </property>
+     </widget>
+     <widget class="QToolButton" name="buttonSwitchOne">
+      <property name="geometry">
+       <rect>
+        <x>197</x>
+        <y>43</y>
+        <width>25</width>
+        <height>31</height>
+       </rect>
+      </property>
+      <property name="inputMethodHints">
+       <set>Qt::ImhNone</set>
+      </property>
+      <property name="text">
+       <string>...</string>
+      </property>
+      <property name="icon">
+       <iconset>
+        <normaloff>../icon/switch/switch-one-enabled.png</normaloff>../icon/switch/switch-one-enabled.png</iconset>
+      </property>
+      <property name="iconSize">
+       <size>
+        <width>30</width>
+        <height>30</height>
+       </size>
+      </property>
+      <property name="autoRaise">
+       <bool>true</bool>
+      </property>
+     </widget>
+     <widget class="QToolButton" name="buttonSwitchTwo">
+      <property name="geometry">
+       <rect>
+        <x>219</x>
+        <y>43</y>
+        <width>21</width>
+        <height>31</height>
+       </rect>
+      </property>
+      <property name="text">
+       <string>...</string>
+      </property>
+      <property name="icon">
+       <iconset>
+        <normaloff>../icon/switch/switch-two-enabled.png</normaloff>../icon/switch/switch-two-enabled.png</iconset>
+      </property>
+      <property name="iconSize">
+       <size>
+        <width>30</width>
+        <height>30</height>
+       </size>
+      </property>
+      <property name="autoRaise">
+       <bool>true</bool>
+      </property>
+     </widget>
+     <widget class="QToolButton" name="buttonSwitchAdaptive">
+      <property name="geometry">
+       <rect>
+        <x>238</x>
+        <y>43</y>
+        <width>25</width>
+        <height>31</height>
+       </rect>
+      </property>
+      <property name="text">
+       <string>...</string>
+      </property>
+      <property name="icon">
+       <iconset>
+        <normaloff>../icon/switch/switch-adaptive-disabled.png</normaloff>../icon/switch/switch-adaptive-disabled.png</iconset>
+      </property>
+      <property name="iconSize">
+       <size>
+        <width>30</width>
+        <height>30</height>
+       </size>
+      </property>
+      <property name="autoRaise">
+       <bool>true</bool>
+      </property>
+     </widget>
+     <zorder>labelDeviceType</zorder>
+     <zorder>labelSignal</zorder>
+     <zorder>labelBattery</zorder>
+     <zorder>buttonSwitchOne</zorder>
+     <zorder>buttonSwitchTwo</zorder>
+     <zorder>buttonSwitchAdaptive</zorder>
+     <zorder>labelModuleID</zorder>
+    </widget>
+   </item>
+   <item>
+    <widget class="QWidget" name="widgetControls" native="true">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="minimumSize">
+      <size>
+       <width>160</width>
+       <height>75</height>
+      </size>
+     </property>
+     <property name="maximumSize">
+      <size>
+       <width>120</width>
+       <height>66</height>
+      </size>
+     </property>
+     <widget class="QLabel" name="labelStatus">
+      <property name="geometry">
+       <rect>
+        <x>-26</x>
+        <y>44</y>
+        <width>181</width>
+        <height>31</height>
+       </rect>
+      </property>
+      <property name="font">
+       <font>
+        <pointsize>10</pointsize>
+        <italic>true</italic>
+       </font>
+      </property>
+      <property name="text">
+       <string>Last Update: 2:30AM</string>
+      </property>
+      <property name="alignment">
+       <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+      </property>
+     </widget>
+     <widget class="QToolButton" name="buttonMenu">
+      <property name="geometry">
+       <rect>
+        <x>131</x>
+        <y>10</y>
+        <width>21</width>
+        <height>36</height>
+       </rect>
+      </property>
+      <property name="text">
+       <string>Activate </string>
+      </property>
+      <property name="autoRaise">
+       <bool>false</bool>
+      </property>
+      <property name="arrowType">
+       <enum>Qt::DownArrow</enum>
+      </property>
+     </widget>
+     <widget class="QToolButton" name="buttonActivate">
+      <property name="geometry">
+       <rect>
+        <x>41</x>
+        <y>10</y>
+        <width>91</width>
+        <height>36</height>
+       </rect>
+      </property>
+      <property name="text">
+       <string>Activate</string>
+      </property>
+      <property name="checkable">
+       <bool>true</bool>
+      </property>
+      <property name="popupMode">
+       <enum>QToolButton::DelayedPopup</enum>
+      </property>
+      <property name="toolButtonStyle">
+       <enum>Qt::ToolButtonTextOnly</enum>
+      </property>
+     </widget>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>

+ 197 - 90
Qt/mainwindow.ui

@@ -222,7 +222,7 @@
        <attribute name="title">
         <string>Settings</string>
        </attribute>
-       <layout class="QFormLayout" name="formLayout">
+       <layout class="QVBoxLayout" name="verticalLayout_2">
         <property name="leftMargin">
          <number>9</number>
         </property>
@@ -235,59 +235,216 @@
         <property name="bottomMargin">
          <number>9</number>
         </property>
-        <item row="0" column="0">
-         <widget class="QLabel" name="labelNetworkBroker">
-          <property name="text">
-           <string>Network Broker:</string>
-          </property>
-         </widget>
-        </item>
-        <item row="0" column="1">
-         <widget class="QLineEdit" name="networkBroker">
-          <property name="placeholderText">
-           <string>URL or IP</string>
-          </property>
+        <item>
+         <widget class="QGroupBox" name="groupNetwork">
+          <property name="title">
+           <string>Network Settings</string>
+          </property>
+          <layout class="QFormLayout" name="formLayout">
+           <item row="0" column="0">
+            <widget class="QLabel" name="labelNetworkBroker">
+             <property name="text">
+              <string>Network Broker:</string>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="1">
+            <widget class="QLineEdit" name="networkBroker">
+             <property name="inputMethodHints">
+              <set>Qt::ImhUrlCharactersOnly</set>
+             </property>
+             <property name="placeholderText">
+              <string>URL or IP</string>
+             </property>
+            </widget>
+           </item>
+           <item row="2" column="1">
+            <widget class="QLineEdit" name="networkPort">
+             <property name="inputMethodHints">
+              <set>Qt::ImhPreferNumbers</set>
+             </property>
+             <property name="text">
+              <string/>
+             </property>
+             <property name="placeholderText">
+              <string>Port</string>
+             </property>
+            </widget>
+           </item>
+           <item row="3" column="0">
+            <widget class="QLabel" name="labelLocalBroker">
+             <property name="text">
+              <string>Local Broker:</string>
+             </property>
+            </widget>
+           </item>
+           <item row="3" column="1">
+            <widget class="QLineEdit" name="localBroker">
+             <property name="inputMethodHints">
+              <set>Qt::ImhUrlCharactersOnly</set>
+             </property>
+             <property name="placeholderText">
+              <string>URL or IP</string>
+             </property>
+            </widget>
+           </item>
+           <item row="5" column="1">
+            <widget class="QLineEdit" name="localPort">
+             <property name="inputMethodHints">
+              <set>Qt::ImhPreferNumbers</set>
+             </property>
+             <property name="placeholderText">
+              <string>Port</string>
+             </property>
+            </widget>
+           </item>
+           <item row="6" column="1">
+            <widget class="QLineEdit" name="otaServer">
+             <property name="text">
+              <string/>
+             </property>
+             <property name="placeholderText">
+              <string>URL or IP</string>
+             </property>
+            </widget>
+           </item>
+           <item row="6" column="0">
+            <widget class="QLabel" name="labelOTA">
+             <property name="text">
+              <string>OTA Server:</string>
+             </property>
+            </widget>
+           </item>
+          </layout>
          </widget>
         </item>
-        <item row="2" column="1">
-         <widget class="QLineEdit" name="networkPort">
-          <property name="text">
-           <string/>
-          </property>
-          <property name="placeholderText">
-           <string>Port</string>
+        <item>
+         <widget class="QDialogButtonBox" name="buttonBoxNetwork">
+          <property name="standardButtons">
+           <set>QDialogButtonBox::Apply|QDialogButtonBox::Discard</set>
           </property>
          </widget>
         </item>
-        <item row="4" column="0">
-         <widget class="QLabel" name="labelLocalBroker">
-          <property name="text">
-           <string>Local Broker:</string>
-          </property>
+        <item alignment="Qt::AlignTop">
+         <widget class="QGroupBox" name="groupDeviceSettings">
+          <property name="title">
+           <string>Device Settings</string>
+          </property>
+          <layout class="QFormLayout" name="formLayout_2">
+           <item row="1" column="0">
+            <widget class="QLabel" name="labelAPSelector">
+             <property name="text">
+              <string>Wi-Fi Access Point:</string>
+             </property>
+            </widget>
+           </item>
+           <item row="1" column="1">
+            <widget class="QSpinBox" name="selectAP">
+             <property name="suffix">
+              <string/>
+             </property>
+             <property name="prefix">
+              <string>Access Point </string>
+             </property>
+             <property name="minimum">
+              <number>1</number>
+             </property>
+             <property name="maximum">
+              <number>5</number>
+             </property>
+            </widget>
+           </item>
+           <item row="2" column="0">
+            <widget class="QLabel" name="labelSSID">
+             <property name="text">
+              <string>SSID:</string>
+             </property>
+            </widget>
+           </item>
+           <item row="2" column="1">
+            <widget class="QLineEdit" name="wifiSSID"/>
+           </item>
+           <item row="3" column="0">
+            <widget class="QLabel" name="labelPassword">
+             <property name="text">
+              <string>Password:</string>
+             </property>
+            </widget>
+           </item>
+           <item row="3" column="1">
+            <widget class="QLineEdit" name="wifiPassword"/>
+           </item>
+          </layout>
          </widget>
         </item>
-        <item row="4" column="1">
-         <widget class="QLineEdit" name="localBroker">
-          <property name="placeholderText">
-           <string>URL or IP</string>
+        <item>
+         <widget class="QDialogButtonBox" name="buttonBoxDevice">
+          <property name="standardButtons">
+           <set>QDialogButtonBox::Cancel|QDialogButtonBox::Save</set>
           </property>
          </widget>
         </item>
-        <item row="6" column="1">
-         <widget class="QLineEdit" name="localPort">
-          <property name="placeholderText">
-           <string>Port</string>
-          </property>
+        <item>
+         <widget class="QGroupBox" name="groupUpdat">
+          <property name="title">
+           <string>WSC Update Settings</string>
+          </property>
+          <layout class="QFormLayout" name="formLayout_3">
+           <item row="0" column="1">
+            <widget class="QLineEdit" name="lineEdit">
+             <property name="placeholderText">
+              <string>URL to GitHub Repository</string>
+             </property>
+            </widget>
+           </item>
+           <item row="1" column="0">
+            <widget class="QPushButton" name="pushButton">
+             <property name="text">
+              <string>Check for Update</string>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="0">
+            <widget class="QLabel" name="label">
+             <property name="text">
+              <string>WSC Software Repository:</string>
+             </property>
+            </widget>
+           </item>
+          </layout>
          </widget>
         </item>
-        <item row="8" column="1">
-         <widget class="QPushButton" name="buttonSettings">
-          <property name="text">
-           <string>Apply Settings</string>
-          </property>
+        <item>
+         <widget class="QGroupBox" name="groupBox_2">
+          <property name="title">
+           <string>Global Commands</string>
+          </property>
+          <layout class="QFormLayout" name="formLayout_4">
+           <item row="0" column="0">
+            <widget class="QLabel" name="label_2">
+             <property name="text">
+              <string>Global Command: </string>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="1">
+            <widget class="QComboBox" name="comboBox">
+             <property name="currentText">
+              <string/>
+             </property>
+            </widget>
+           </item>
+           <item row="1" column="0">
+            <widget class="QPushButton" name="pushButton_2">
+             <property name="text">
+              <string>Send Command</string>
+             </property>
+            </widget>
+           </item>
+          </layout>
          </widget>
         </item>
-        <item row="9" column="0">
+        <item>
          <spacer name="verticalSpacer">
           <property name="orientation">
            <enum>Qt::Vertical</enum>
@@ -300,56 +457,6 @@
           </property>
          </spacer>
         </item>
-        <item row="10" column="0">
-         <widget class="QLabel" name="labelAPSelector">
-          <property name="text">
-           <string>Wi-Fi Access Point:</string>
-          </property>
-         </widget>
-        </item>
-        <item row="10" column="1">
-         <widget class="QSpinBox" name="selectAP">
-          <property name="suffix">
-           <string/>
-          </property>
-          <property name="prefix">
-           <string>AP </string>
-          </property>
-          <property name="minimum">
-           <number>1</number>
-          </property>
-          <property name="maximum">
-           <number>5</number>
-          </property>
-         </widget>
-        </item>
-        <item row="11" column="0">
-         <widget class="QLabel" name="labelSSID">
-          <property name="text">
-           <string>SSID:</string>
-          </property>
-         </widget>
-        </item>
-        <item row="11" column="1">
-         <widget class="QLineEdit" name="wifiSSID"/>
-        </item>
-        <item row="13" column="0">
-         <widget class="QLabel" name="labelPassword">
-          <property name="text">
-           <string>Password:</string>
-          </property>
-         </widget>
-        </item>
-        <item row="13" column="1">
-         <widget class="QLineEdit" name="wifiPassword"/>
-        </item>
-        <item row="15" column="1">
-         <widget class="QPushButton" name="buttonTrainDevice">
-          <property name="text">
-           <string>Train IdeasX Device</string>
-          </property>
-         </widget>
-        </item>
        </layout>
       </widget>
      </widget>

+ 4 - 4
icon/svg/icons.svg

@@ -171,9 +171,9 @@
      borderopacity="1.0"
      inkscape:pageopacity="0.0"
      inkscape:pageshadow="2"
-     inkscape:zoom="1.979899"
-     inkscape:cx="536.54911"
-     inkscape:cy="783.28572"
+     inkscape:zoom="1.4"
+     inkscape:cx="422.21631"
+     inkscape:cy="856.43925"
      inkscape:document-units="px"
      inkscape:current-layer="layer1"
      showgrid="true"
@@ -1279,7 +1279,7 @@
     <g
        style="display:inline;opacity:0.97000002"
        id="g4965-3"
-       transform="matrix(1.5767125,0,0,1.5993259,5240.4895,654.5936)"
+       transform="matrix(1.5767125,0,0,1.5993259,4671.1786,584.85131)"
        inkscape:export-filename="/home/tyler/ideasX-repositories/ideasX-workstation-client-v2/icon/devicetype/modulev3b.png"
        inkscape:export-xdpi="74.398445"
        inkscape:export-ydpi="74.398445">

+ 240 - 0
mainwindow2.py

@@ -0,0 +1,240 @@
+# -*- coding: utf-8 -*-
+
+# Form implementation generated from reading ui file 'mainwindow.ui'
+#
+# Created by: PyQt5 UI code generator 5.7
+#
+# 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(525, 648)
+        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
+        sizePolicy.setHorizontalStretch(0)
+        sizePolicy.setVerticalStretch(0)
+        sizePolicy.setHeightForWidth(MainWindow.sizePolicy().hasHeightForWidth())
+        MainWindow.setSizePolicy(sizePolicy)
+        MainWindow.setDocumentMode(False)
+        MainWindow.setDockNestingEnabled(True)
+        MainWindow.setDockOptions(QtWidgets.QMainWindow.AllowNestedDocks|QtWidgets.QMainWindow.AllowTabbedDocks|QtWidgets.QMainWindow.AnimatedDocks|QtWidgets.QMainWindow.VerticalTabs)
+        MainWindow.setUnifiedTitleAndToolBarOnMac(False)
+        self.centralwidget = QtWidgets.QWidget(MainWindow)
+        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
+        sizePolicy.setHorizontalStretch(0)
+        sizePolicy.setVerticalStretch(0)
+        sizePolicy.setHeightForWidth(self.centralwidget.sizePolicy().hasHeightForWidth())
+        self.centralwidget.setSizePolicy(sizePolicy)
+        self.centralwidget.setObjectName("centralwidget")
+        self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
+        self.verticalLayout.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint)
+        self.verticalLayout.setSpacing(6)
+        self.verticalLayout.setObjectName("verticalLayout")
+        self.tabWidget = QtWidgets.QTabWidget(self.centralwidget)
+        self.tabWidget.setContextMenuPolicy(QtCore.Qt.DefaultContextMenu)
+        self.tabWidget.setLayoutDirection(QtCore.Qt.LeftToRight)
+        self.tabWidget.setAutoFillBackground(True)
+        self.tabWidget.setTabPosition(QtWidgets.QTabWidget.West)
+        self.tabWidget.setElideMode(QtCore.Qt.ElideNone)
+        self.tabWidget.setDocumentMode(False)
+        self.tabWidget.setTabBarAutoHide(True)
+        self.tabWidget.setObjectName("tabWidget")
+        self.tabEncoder = QtWidgets.QWidget()
+        self.tabEncoder.setMaximumSize(QtCore.QSize(16777215, 16777215))
+        self.tabEncoder.setObjectName("tabEncoder")
+        self.gridLayout = QtWidgets.QGridLayout(self.tabEncoder)
+        self.gridLayout.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint)
+        self.gridLayout.setContentsMargins(9, 9, 9, 9)
+        self.gridLayout.setObjectName("gridLayout")
+        self.searchEncoder = QtWidgets.QLineEdit(self.tabEncoder)
+        self.searchEncoder.setClearButtonEnabled(True)
+        self.searchEncoder.setObjectName("searchEncoder")
+        self.gridLayout.addWidget(self.searchEncoder, 1, 2, 1, 1)
+        spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
+        self.gridLayout.addItem(spacerItem, 1, 1, 1, 1)
+        self.scrollEncoder = QtWidgets.QScrollArea(self.tabEncoder)
+        self.scrollEncoder.setAutoFillBackground(False)
+        self.scrollEncoder.setStyleSheet("")
+        self.scrollEncoder.setWidgetResizable(True)
+        self.scrollEncoder.setObjectName("scrollEncoder")
+        self.contentEncoder = QtWidgets.QWidget()
+        self.contentEncoder.setGeometry(QtCore.QRect(0, 0, 459, 556))
+        self.contentEncoder.setObjectName("contentEncoder")
+        self.scrollEncoder.setWidget(self.contentEncoder)
+        self.gridLayout.addWidget(self.scrollEncoder, 0, 0, 1, 3)
+        self.tabWidget.addTab(self.tabEncoder, "")
+        self.tabActuator = QtWidgets.QWidget()
+        self.tabActuator.setObjectName("tabActuator")
+        self.gridLayout_2 = QtWidgets.QGridLayout(self.tabActuator)
+        self.gridLayout_2.setContentsMargins(9, 9, 9, 9)
+        self.gridLayout_2.setObjectName("gridLayout_2")
+        spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
+        self.gridLayout_2.addItem(spacerItem1, 1, 0, 1, 1)
+        self.searchActuator = QtWidgets.QLineEdit(self.tabActuator)
+        self.searchActuator.setAutoFillBackground(False)
+        self.searchActuator.setFrame(True)
+        self.searchActuator.setClearButtonEnabled(True)
+        self.searchActuator.setObjectName("searchActuator")
+        self.gridLayout_2.addWidget(self.searchActuator, 1, 1, 1, 1)
+        self.tableActuator = QtWidgets.QTableView(self.tabActuator)
+        self.tableActuator.setEnabled(True)
+        self.tableActuator.setFrameShadow(QtWidgets.QFrame.Plain)
+        self.tableActuator.setAlternatingRowColors(True)
+        self.tableActuator.setShowGrid(False)
+        self.tableActuator.setSortingEnabled(True)
+        self.tableActuator.setObjectName("tableActuator")
+        self.tableActuator.horizontalHeader().setStretchLastSection(True)
+        self.tableActuator.verticalHeader().setVisible(False)
+        self.gridLayout_2.addWidget(self.tableActuator, 0, 0, 1, 2)
+        self.tabWidget.addTab(self.tabActuator, "")
+        self.tabSetting = QtWidgets.QWidget()
+        self.tabSetting.setObjectName("tabSetting")
+        self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.tabSetting)
+        self.verticalLayout_2.setContentsMargins(9, 9, 9, 9)
+        self.verticalLayout_2.setObjectName("verticalLayout_2")
+        self.groupNetwork = QtWidgets.QGroupBox(self.tabSetting)
+        self.groupNetwork.setObjectName("groupNetwork")
+        self.formLayout = QtWidgets.QFormLayout(self.groupNetwork)
+        self.formLayout.setObjectName("formLayout")
+        self.labelNetworkBroker = QtWidgets.QLabel(self.groupNetwork)
+        self.labelNetworkBroker.setObjectName("labelNetworkBroker")
+        self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.labelNetworkBroker)
+        self.networkBroker = QtWidgets.QLineEdit(self.groupNetwork)
+        self.networkBroker.setInputMethodHints(QtCore.Qt.ImhUrlCharactersOnly)
+        self.networkBroker.setObjectName("networkBroker")
+        self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.networkBroker)
+        self.networkPort = QtWidgets.QLineEdit(self.groupNetwork)
+        self.networkPort.setInputMethodHints(QtCore.Qt.ImhPreferNumbers)
+        self.networkPort.setText("")
+        self.networkPort.setObjectName("networkPort")
+        self.formLayout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.networkPort)
+        self.labelLocalBroker = QtWidgets.QLabel(self.groupNetwork)
+        self.labelLocalBroker.setObjectName("labelLocalBroker")
+        self.formLayout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.labelLocalBroker)
+        self.localBroker = QtWidgets.QLineEdit(self.groupNetwork)
+        self.localBroker.setInputMethodHints(QtCore.Qt.ImhUrlCharactersOnly)
+        self.localBroker.setObjectName("localBroker")
+        self.formLayout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.localBroker)
+        self.localPort = QtWidgets.QLineEdit(self.groupNetwork)
+        self.localPort.setInputMethodHints(QtCore.Qt.ImhPreferNumbers)
+        self.localPort.setObjectName("localPort")
+        self.formLayout.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.localPort)
+        self.otaServer = QtWidgets.QLineEdit(self.groupNetwork)
+        self.otaServer.setText("")
+        self.otaServer.setObjectName("otaServer")
+        self.formLayout.setWidget(6, QtWidgets.QFormLayout.FieldRole, self.otaServer)
+        self.labelOTA = QtWidgets.QLabel(self.groupNetwork)
+        self.labelOTA.setObjectName("labelOTA")
+        self.formLayout.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.labelOTA)
+        self.verticalLayout_2.addWidget(self.groupNetwork)
+        self.buttonBoxNetwork = QtWidgets.QDialogButtonBox(self.tabSetting)
+        self.buttonBoxNetwork.setStandardButtons(QtWidgets.QDialogButtonBox.Apply|QtWidgets.QDialogButtonBox.Discard)
+        self.buttonBoxNetwork.setObjectName("buttonBoxNetwork")
+        self.verticalLayout_2.addWidget(self.buttonBoxNetwork)
+        self.groupDeviceSettings = QtWidgets.QGroupBox(self.tabSetting)
+        self.groupDeviceSettings.setObjectName("groupDeviceSettings")
+        self.formLayout_2 = QtWidgets.QFormLayout(self.groupDeviceSettings)
+        self.formLayout_2.setObjectName("formLayout_2")
+        self.labelAPSelector = QtWidgets.QLabel(self.groupDeviceSettings)
+        self.labelAPSelector.setObjectName("labelAPSelector")
+        self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.labelAPSelector)
+        self.selectAP = QtWidgets.QSpinBox(self.groupDeviceSettings)
+        self.selectAP.setSuffix("")
+        self.selectAP.setMinimum(1)
+        self.selectAP.setMaximum(5)
+        self.selectAP.setObjectName("selectAP")
+        self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.selectAP)
+        self.labelSSID = QtWidgets.QLabel(self.groupDeviceSettings)
+        self.labelSSID.setObjectName("labelSSID")
+        self.formLayout_2.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.labelSSID)
+        self.wifiSSID = QtWidgets.QLineEdit(self.groupDeviceSettings)
+        self.wifiSSID.setObjectName("wifiSSID")
+        self.formLayout_2.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.wifiSSID)
+        self.labelPassword = QtWidgets.QLabel(self.groupDeviceSettings)
+        self.labelPassword.setObjectName("labelPassword")
+        self.formLayout_2.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.labelPassword)
+        self.wifiPassword = QtWidgets.QLineEdit(self.groupDeviceSettings)
+        self.wifiPassword.setObjectName("wifiPassword")
+        self.formLayout_2.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.wifiPassword)
+        self.verticalLayout_2.addWidget(self.groupDeviceSettings, 0, QtCore.Qt.AlignTop)
+        self.buttonBoxDevice = QtWidgets.QDialogButtonBox(self.tabSetting)
+        self.buttonBoxDevice.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Save)
+        self.buttonBoxDevice.setObjectName("buttonBoxDevice")
+        self.verticalLayout_2.addWidget(self.buttonBoxDevice)
+        self.groupUpdat = QtWidgets.QGroupBox(self.tabSetting)
+        self.groupUpdat.setObjectName("groupUpdat")
+        self.formLayout_3 = QtWidgets.QFormLayout(self.groupUpdat)
+        self.formLayout_3.setObjectName("formLayout_3")
+        self.lineEdit = QtWidgets.QLineEdit(self.groupUpdat)
+        self.lineEdit.setObjectName("lineEdit")
+        self.formLayout_3.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.lineEdit)
+        self.pushButton = QtWidgets.QPushButton(self.groupUpdat)
+        self.pushButton.setObjectName("pushButton")
+        self.formLayout_3.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.pushButton)
+        self.label = QtWidgets.QLabel(self.groupUpdat)
+        self.label.setObjectName("label")
+        self.formLayout_3.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label)
+        self.verticalLayout_2.addWidget(self.groupUpdat)
+        self.groupBox_2 = QtWidgets.QGroupBox(self.tabSetting)
+        self.groupBox_2.setObjectName("groupBox_2")
+        self.formLayout_4 = QtWidgets.QFormLayout(self.groupBox_2)
+        self.formLayout_4.setObjectName("formLayout_4")
+        self.label_2 = QtWidgets.QLabel(self.groupBox_2)
+        self.label_2.setObjectName("label_2")
+        self.formLayout_4.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label_2)
+        self.comboBox = QtWidgets.QComboBox(self.groupBox_2)
+        self.comboBox.setCurrentText("")
+        self.comboBox.setObjectName("comboBox")
+        self.formLayout_4.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.comboBox)
+        self.pushButton_2 = QtWidgets.QPushButton(self.groupBox_2)
+        self.pushButton_2.setObjectName("pushButton_2")
+        self.formLayout_4.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.pushButton_2)
+        self.verticalLayout_2.addWidget(self.groupBox_2)
+        spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
+        self.verticalLayout_2.addItem(spacerItem2)
+        self.tabWidget.addTab(self.tabSetting, "")
+        self.verticalLayout.addWidget(self.tabWidget)
+        MainWindow.setCentralWidget(self.centralwidget)
+        self.statusbar = QtWidgets.QStatusBar(MainWindow)
+        self.statusbar.setEnabled(True)
+        self.statusbar.setToolTipDuration(-7)
+        self.statusbar.setLayoutDirection(QtCore.Qt.RightToLeft)
+        self.statusbar.setObjectName("statusbar")
+        MainWindow.setStatusBar(self.statusbar)
+
+        self.retranslateUi(MainWindow)
+        self.tabWidget.setCurrentIndex(2)
+        QtCore.QMetaObject.connectSlotsByName(MainWindow)
+
+    def retranslateUi(self, MainWindow):
+        _translate = QtCore.QCoreApplication.translate
+        MainWindow.setWindowTitle(_translate("MainWindow", "IdeasX Workstation Client"))
+        self.searchEncoder.setPlaceholderText(_translate("MainWindow", "Search for Encoders..."))
+        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabEncoder), _translate("MainWindow", "Encoders"))
+        self.searchActuator.setPlaceholderText(_translate("MainWindow", "Search for Actuator"))
+        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabActuator), _translate("MainWindow", "Actuators"))
+        self.groupNetwork.setTitle(_translate("MainWindow", "Network Settings"))
+        self.labelNetworkBroker.setText(_translate("MainWindow", "Network Broker:"))
+        self.networkBroker.setPlaceholderText(_translate("MainWindow", "URL or IP"))
+        self.networkPort.setPlaceholderText(_translate("MainWindow", "Port"))
+        self.labelLocalBroker.setText(_translate("MainWindow", "Local Broker:"))
+        self.localBroker.setPlaceholderText(_translate("MainWindow", "URL or IP"))
+        self.localPort.setPlaceholderText(_translate("MainWindow", "Port"))
+        self.otaServer.setPlaceholderText(_translate("MainWindow", "URL or IP"))
+        self.labelOTA.setText(_translate("MainWindow", "OTA Server:"))
+        self.groupDeviceSettings.setTitle(_translate("MainWindow", "Device Settings"))
+        self.labelAPSelector.setText(_translate("MainWindow", "Wi-Fi Access Point:"))
+        self.selectAP.setPrefix(_translate("MainWindow", "Access Point "))
+        self.labelSSID.setText(_translate("MainWindow", "SSID:"))
+        self.labelPassword.setText(_translate("MainWindow", "Password:"))
+        self.groupUpdat.setTitle(_translate("MainWindow", "WSC Update Settings"))
+        self.lineEdit.setPlaceholderText(_translate("MainWindow", "URL to GitHub Repository"))
+        self.pushButton.setText(_translate("MainWindow", "Check for Update"))
+        self.label.setText(_translate("MainWindow", "WSC Software Repository:"))
+        self.groupBox_2.setTitle(_translate("MainWindow", "Global Commands"))
+        self.label_2.setText(_translate("MainWindow", "Global Command: "))
+        self.pushButton_2.setText(_translate("MainWindow", "Send Command"))
+        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabSetting), _translate("MainWindow", "Settings"))
+

+ 0 - 222
wsc_backend.py

@@ -1,222 +0,0 @@
-#!/usr/bin/python
-
-'''
- 
-WORKSTATION CLIENT BACKEND
-
-'''
-
-
-import sys
-try:
-    import paho.mqtt.client as mqtt
-except ImportError:
-    # This part is only required to run the example from within the examples
-    # directory when the module itself is not installed.
-    #
-    # If you have the module installed, just use "import paho.mqtt.client"
-    import os
-    import inspect
-    cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],"../src")))
-    if cmd_subfolder not in sys.path:
-        sys.path.insert(0, cmd_subfolder)
-    import paho.mqtt.client as mqtt
-# NOTE: This needs to be replaced with a QT, TKinker alternative. 
-# from wx.lib.pubsub import pub
-from packet_handling import decode_client_list, decode_data_packet
-try: 
-    from ctype_bindings import SwitchPro6
-    windows = True
-except AttributeError: 
-    print("Windows win32 API missing.\n Button presses will be still be represented in print statements.") 
-    global print_debug 
-    windows = False
-
-#------------------------------------------------------------------------------
-# WORKSTATIONCLIENT CLASS
-
-class WorkstationClientClass():
-    def __init__(self, client_id=None, debug=True, mqttdebug=False):
-        self.client_id = client_id 
-        self.debug = debug
-        self.mqttdebug = mqttdebug
-        self.mode_color = 'debug'
-            
-        self.data_topics = '/modules/+/data'
-        self.clientlist_topic = '/workstations/modulehealth'
-        self.clientlist = None 
-        self.subscribed_modules = []
-        if windows:
-            self.switchpro6 = SwitchPro6()
-        self._mqttc = mqtt.Client(self.client_id, clean_session=True, userdata=None, 
-                        protocol='MQTTv311')
-        self._mqttc.message_callback_add(self.clientlist_topic, self.mqtt_on_client_list) 
-        self._mqttc.message_callback_add(self.data_topics, self.mqtt_on_data)
-        self._mqttc.on_connect = self.mqtt_on_connect
-        self._mqttc.on_disconnect = self.mqtt_on_disconnect        
-        if self.mqttdebug: 
-            self._mqttc.on_log = self.mqtt_on_log
-            
-#------------------------------------------------------------------------------
-# callback functions
-
-    def mqtt_on_connect(self, mqttc, backend_data, flags, rc):
-        # pub.sendMessage('status.connection', status = [mqttc._host, mqttc._port, rc])
-        if self.debug: 
-            if rc == 0: 
-                print('Connected to %s: %s' % (mqttc._host, mqttc._port))
-            else: 
-                print('rc: ' + str(rc))
-
-    def mqtt_on_client_list(self, mqttc, backend_data, msg):
-        self.clientlist = decode_client_list(msg.payload) 
-        
-        for active_module_id in self.subscribed_modules: 
-            for dead_module_id in self.clientlist[self.clientlist['alive']==0]['module_id']: 
-                if active_module_id == dead_module_id: 
-                    if self.debug: 
-                        print("Conflicting ID: " + str(active_module_id)+ \
-                        "\nAttempting to kill now.")
-                    self.unsubscribe_to_module(active_module_id)
-        if self.debug: 
-            print(self.clientlist)
-        # pub.sendMessage('data.clientlist', data = self.clientlist)
-       
-        
-    def mqtt_on_data(self, mqttc, backend_data, msg):
-        #pub.sendMessage('data.module', data=msg.payload)
-        data =  decode_data_packet(msg.payload)
-        if windows:     
-            self.switchpro6.keymap_press(data[0])
-        if self.debug: 
-            print(msg.topic+" "+str(msg.qos)+" "+str(msg.payload)+" "+str(data))
-
-    def mqtt_on_log(self, mqttc, backend_data, level, string):
-        print(string)
-    
-    def mqtt_on_disconnect(self, mqttc, backend_data, rc):
-        # pub.sendMessage('status.connection', status = [None, None, rc])
-        if self.debug: 
-            if rc != 0: 
-                print("Client disconnected and its a mystery why!")
-            else: 
-                print("Client successfully disconnected.") 
-#------------------------------------------------------------------------------
-# General API Calls 
-        
-    def start_workstation_client(self, ip="127.0.0.1", port=1883, keepalive=60):     
-        self.ip = ip 
-        self.port = port 
-        self.keepalive = keepalive 
-        self.clientlist = None
-        self._mqttc.connect(ip, port, keepalive)      # connect to broker                              
-        self._mqttc.subscribe(self.clientlist_topic, 2)    # subscribe to client list 
-        self._mqttc.loop_start() # Start a thread handling network traffic   
-    
-    def subscribe_to_module(self, module_id): 
-        module_found = False
-        if type(module_id) == int: 
-            module_id = str(module_id) 
-        if len(module_id) < 8:
-            module_id = '0'*(8-len(module_id)) + module_id
-	
-        for active_module_id in self.clientlist[self.clientlist['alive']==1]['module_id']:
-            if int(module_id) == active_module_id: 
-                module_found = True
-                module_topic = '/modules/'+module_id+'/data'
-                result, mid =  self._mqttc.subscribe(module_topic, qos=0)
-                # pub.sendMessage('status.subscribe', status=[int(module_id), result, mid])
-                if result == 0:
-                    if int(module_id) not in self.subscribed_modules: 
-                        self.subscribed_modules.append(int(module_id))
-                        #pub.sendMessage('data.subscribed_modules', data=self.subscribed_modules)
-                        if self.debug: 
-                            print("Module %s was successfully added" % module_id)
-                    else: 
-                        if self.debug: 
-                            print("Module is already subscribed")
-                return result, mid
-        if module_found == False:
-            if self.debug: 
-                print("Module is not alive or in client list.") 
-                print("Module ID: " + str(module_id))
-                return 3, None 
-        
-    def unsubscribe_to_module(self, module_id): 
-        if type(module_id) == int: 
-            module_id = str(module_id) 
-        if len(module_id) < 8:
-            module_id = '0'*(8-len(module_id)) + module_id
-        
-        if int(module_id) in self.subscribed_modules: 
-            module_topic = '/modules/'+module_id+'/data'
-            result, mid = self._mqttc.unsubscribe(module_topic)
-            # pub.sendMessage('status.unsubscribe', status=[int(module_id), result, mid])
-            if result == 0: 
-                self.subscribed_modules.remove(int(module_id))
-                #pub.sendMessage('data.subscribed_modules', data=self.subscribed_modules)    # send all the subs
-                if self.debug: 
-                    print("Module %s was successfully removed" % module_id)
-            return result, mid            
-        else:            
-            if self.debug: 
-                print("Module is not subscribed") 
-                print("Subscribed Modules:\n", self.subscribed_modules)
-            return 3, None 
-
-#-----------------------------------------------------------------------------
-# Puck Connectivity 	
-# The Puck will function under the following methods. 
-# 1. The puck will make the system aware of it's presence through a health 
-#    message to the database client. There needs to be sometype of addition
-#    flag or delimiter for the database client to know it is a puck. 
-# 2. The backend needs to forward this flag via pubsub. 
-# 3. There needs to be function to pair a module to a puck with the following
-#    house keeping skills: 
-#    a. Automatically unpairs if module or puck dies 
-#    b. will not pair if puck or module is already connected to computer or 
-#       paired with another computer. 
-#    c. sends a message to puck to listen to the topic of a specific module. 
-#    d. confirms puck is listening through sometype of verification QoS = 2? 
-# 
-
-    def pair_module_to_puck(self, module_id, puck_id, pair=True):
-        if type(module_id) == int: 
-            module_id = str(module_id)
-        if len(module_id)<8: 
-            module_id = '0'*(8-len(module_id)) + module_id         
-        if type(puck_id) == int: 
-            puck_id = str(puck_id)
-        if len(puck_id)<8: 
-            puck_id = '0'*(8-len(puck_id)) + puck_id 
-        
-        module_found = False
-        # update to insure puck is alive
-        # modifiy so pandas only is loooking at modules
-        for active_module_id in self.clientlist[self.clientlist['alive']==1]['module_id']:
-            if int(module_id) == active_module_id :
-                module_found = True 
-                puck_topic = '/pucks/'+puck_id+'/command'
-                if pair:
-                    payload = 'a/modules/'+str(module_id)+'/data'
-                else: 
-                    payload = 'd/modules/'+str(module_id)+'/data'
-                result, mid =  self._mqttc.publish(puck_topic, payload, 0, retain=False)
-                if result == 0: 
-                    # self.subscribed_modules.remove(int(module_id))
-                    # pub.sendMessage('data.paired_modules', data=self.subscribed_modules)    # send all the subs
-                    if self.debug: 
-                        print("Module %s was successfully paired" % module_id)
-                    return result, mid    
-
-        if module_found == False:
-            if self.debug: 
-                print("Module is not alive or in client list.")
-                print("Module ID: " + str(module_id))
-                return 3, None 
-        
-        
-                
-if __name__ == "__main__": 
-    wsc = WorkstationClientClass() 
-    wsc.start_workstation_client(ip="server.ideasx.tech")