IdeasXWSCView.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. import sys
  2. import time
  3. import sip
  4. from PyQt5 import QtCore, QtGui, QtWidgets
  5. from mainwindow import Ui_MainWindow
  6. from ideasxdevice import Ui_IdeasXDevice
  7. from IdeasXWSCBackend import IdeasXWSCNetworkThread
  8. from ParsingTools import ParsingTools
  9. from encoderconfigurationdialog import Ui_SwitchConfigDialog
  10. class IdeasXSwitchDialog(QtWidgets.QDialog):
  11. def __init__(self, switch, assignedKey):
  12. super(IdeasXSwitchDialog, self).__init__()
  13. self.__ui = Ui_SwitchConfigDialog()
  14. self.__ui.setupUi(self)
  15. self.__ui.buttonApply.clicked.connect(self.submitOnClose)
  16. self.key = assignedKey[0]
  17. self.enable = assignedKey[1]
  18. self.switch = switch
  19. self.__ui.checkSwitchEnable.setChecked(self.enable)
  20. self.__ui.lineSwitchKey.setText(self.key)
  21. def submitOnClose(self):
  22. self.key = self.__ui.lineSwitchKey.text()
  23. self.enable = self.__ui.checkSwitchEnable.isChecked()
  24. self.accept()
  25. class IdeasXDeviceManager():
  26. def __init__(self, deviceClass, wsc):
  27. self.__devices = {}
  28. self.__deviceClass = deviceClass
  29. self.__deviceLayout = QtWidgets.QVBoxLayout()
  30. self.__deviceLayout.setAlignment(QtCore.Qt.AlignTop)
  31. self.__deviceLayout.setContentsMargins(9, 0, 9, 0)
  32. self.__deviceLayout.setSpacing(0)
  33. self.__wsc = wsc
  34. def refreshDevices(self, devices):
  35. for deviceMAC in list(devices.keys()):
  36. if deviceMAC in self.__devices.keys():
  37. print("Updating Device")
  38. self.__devices[deviceMAC].updateDevice(devices[deviceMAC])
  39. else:
  40. print("Adding Device")
  41. self.__devices[deviceMAC] = self.__deviceClass(devices[deviceMAC], self.__wsc)
  42. self.__deviceLayout.addWidget(self.__devices[deviceMAC])
  43. for deviceMAC in list(self.__devices.keys()):
  44. if deviceMAC not in devices.keys():
  45. print("Removing Device")
  46. self.removeDevice(deviceMAC)
  47. def removeDevice(self, deviceMAC):
  48. self.__deviceLayout.removeWidget(self.__devices[deviceMAC])
  49. sip.delete(self.__devices[deviceMAC])
  50. self.__devices.pop(deviceMAC)
  51. def returnLayout(self):
  52. return self.__deviceLayout
  53. def filterDevices(self, searchPhase):
  54. print("This currently doesn't work")
  55. def printDevices(self):
  56. print(self.__devices)
  57. class IdeasXEncoder(QtWidgets.QWidget):
  58. sendCommand = QtCore.pyqtSignal(['QString'], name='sendCommand')
  59. def __init__(self, encoder, wsc):
  60. # This should become a static variable for the class
  61. self.__pathToIcon = {'network': './icon/network/',
  62. 'battery': './icon/battery/',
  63. 'battery_charging': './icon/battery/',
  64. 'switch': './icon/switch/'
  65. }
  66. self.__icon = {'network': ['network-wireless-offline-symbolic.png',
  67. 'network-wireless-signal-weak-symbolic.png',
  68. 'network-wireless-signal-ok-symbolic.png',
  69. 'network-wireless-signal-good-symbolic.png',
  70. 'network-wireless-signal-excellent-symbolic.png'],
  71. 'battery': ['battery-empty-symbolic.png',
  72. 'battery-caution-symbolic.png',
  73. 'battery-low-symbolic.png',
  74. 'battery-good-symbolic.png',
  75. 'battery-full-symbolic.png'],
  76. 'battery_charging': ['battery-empty-charging-symbolic.png',
  77. 'battery-caution-charging-symbolic.png',
  78. 'battery-low-charging-symbolic.png',
  79. 'battery-good-charging-symbolic.png',
  80. 'battery-full-charged-symbolic.png'],
  81. 'switch': ['switch-one-enabled.png',
  82. 'switch-one-disabled.png',
  83. 'switch-two-enabled.png',
  84. 'switch-two-disabled.png',
  85. 'switch-adaptive-enabled.png',
  86. 'switch-adaptive-disabled.png']
  87. }
  88. self.__deviceType = 'encoder'
  89. self.__wsc = wsc
  90. # Setup UI components
  91. super(IdeasXEncoder, self).__init__()
  92. self.__ui = Ui_IdeasXDevice()
  93. self.__ui.setupUi(self)
  94. self._parserTools = ParsingTools()
  95. self.updateDevice(encoder)
  96. self.updateSwitchIcons()
  97. # Setup Signals
  98. self.setupMenu()
  99. self.__ui.buttonActivate.clicked.connect(self.activateEncoder)
  100. self.__ui.buttonSwitchOne.clicked.connect(lambda: self.openSwitchDialog(self.__wsc.keyEmulator.switchOne,
  101. self.__wsc.keyEmulator.getAssignedKey(self.__strModuleID, self.__wsc.keyEmulator.switchOne)))
  102. self.__ui.buttonSwitchTwo.clicked.connect(lambda: self.openSwitchDialog(self.__wsc.keyEmulator.switchTwo,
  103. self.__wsc.keyEmulator.getAssignedKey(self.__strModuleID, self.__wsc.keyEmulator.switchTwo)))
  104. def openSwitchDialog(self, switch, assignedKey):
  105. dialog = IdeasXSwitchDialog(switch, assignedKey)
  106. if dialog.exec_():
  107. if dialog.key != None and len(dialog.key) == 1:
  108. self.__wsc.keyEmulator.assignKey(self.__strModuleID, dialog.switch, dialog.key, dialog.enable)
  109. self.updateSwitchIcons()
  110. def setupSwitchIcon(self, path):
  111. icon = QtGui.QIcon()
  112. iconPath = self.__pathToIcon['switch']
  113. iconPath = iconPath + path
  114. icon.addPixmap(QtGui.QPixmap(iconPath), QtGui.QIcon.Normal, QtGui.QIcon.Off)
  115. return icon
  116. def setupMenu(self):
  117. shutdownAction = QtWidgets.QAction('Shutdown Encoder', self)
  118. shutdownAction.triggered.connect(lambda: self.__wsc.shutdownDevice(self.__strModuleID, None))
  119. testKeysAction = QtWidgets.QAction("Test Keys", self)
  120. testKeysAction.triggered.connect(self.testKeys)
  121. deviceMenu = QtWidgets.QMenu()
  122. #deviceMenu.addSection("General Actions")
  123. #deviceMenu.addAction("Pair Encoder with Actuator")
  124. #deviceMenu.addAction("Train Adaptive Switch")
  125. #deviceMenu.addAction("Configure Module")
  126. deviceMenu.addSection("Encoder Commands")
  127. deviceMenu.addAction(shutdownAction)
  128. #deviceMenu.addAction("Restart Encoder")
  129. #deviceMenu.addAction("Update Firmware")
  130. deviceMenu.addSection("Engineering Tools")
  131. deviceMenu.addAction(testKeysAction)
  132. self.__ui.buttonMenu.setPopupMode(2)
  133. self.__ui.buttonMenu.setMenu(deviceMenu)
  134. self.__ui.buttonMenu.setStyleSheet("* { padding-right: 3px } QToolButton::menu-indicator { image: none }")
  135. def activateEncoder(self):
  136. if self.__ui.buttonActivate.text() == "Activate":
  137. print("Activating Encoder: " + self.__ui.labelModuleID.text())
  138. self.__ui.buttonActivate.setText("Deactivate")
  139. else:
  140. print("Deactivating Encoder: " + self.__ui.labelModuleID.text())
  141. self.__ui.buttonActivate.setText("Activate")
  142. def updateDevice(self, encoder):
  143. self.__rssi = encoder['rssi']
  144. self.__soc = self._parserTools.calculateSOC(encoder['soc'])
  145. self.__vcell = self._parserTools.calculateVCell(encoder['vcell'])
  146. self.__strModuleID = self._parserTools.macToString(encoder['module_id'])
  147. self.__updateTime = encoder['time']
  148. self.setModuleID(self.__strModuleID)
  149. self.setSOCIcon(self.__soc)
  150. self.setRSSIIcon(self.__rssi)
  151. self.setStatusTime(self.__updateTime)
  152. def setModuleID(self, strModuleID):
  153. self.__ui.labelModuleID.setText(strModuleID)
  154. def setSOCIcon(self, soc):
  155. if soc >= 75:
  156. batteryIcon = 4
  157. elif soc >= 50 and soc < 75:
  158. batteryIcon = 3
  159. elif soc >= 25 and soc < 50:
  160. batteryIcon = 2
  161. elif soc >=10 and soc < 25:
  162. batteryIcon = 1
  163. elif soc < 10:
  164. batteryIcon = 0
  165. batteryIcon = self.__pathToIcon['battery']+self.__icon['battery'][batteryIcon]
  166. self.__ui.labelBattery.setPixmap(QtGui.QPixmap(batteryIcon))
  167. self.__ui.labelBattery.setToolTip(str(soc) + "%")
  168. def setStatusTime(self, updateTime):
  169. # set last update time or date
  170. lastUpdate = time.ctime(updateTime).split(" ")
  171. currentTime = time.ctime().split(" ")
  172. if currentTime[1] != lastUpdate[1] or currentTime[2] != lastUpdate[2] or currentTime[4] != lastUpdate[4]:
  173. lastUpdate = lastUpdate[1] + " " + lastUpdate[2] + " " + lastUpdate[4]
  174. else:
  175. lastUpdate = lastUpdate[3]
  176. self.__ui.labelStatus.setText("Last Update: " + lastUpdate)
  177. def setRSSIIcon(self, rssi):
  178. # set rssi icon
  179. if rssi >= -50:
  180. rssiIcon = 4
  181. elif rssi >= -60 and rssi < -50:
  182. rssiIcon = 3
  183. elif rssi >= -70 and rssi < -60:
  184. rssiIcon = 2
  185. elif rssi < -70:
  186. rssiIcon = 1
  187. rssiIcon = self.__pathToIcon['network'] + self.__icon['network'][rssiIcon]
  188. self.__ui.labelSignal.setPixmap(QtGui.QPixmap(rssiIcon))
  189. self.__ui.labelSignal.setToolTip(str(rssi) + " dBm")
  190. def updateSwitchIcons(self):
  191. keys = self.__wsc.keyEmulator.getAssignedKeys(self.__strModuleID)
  192. if keys[self.__wsc.keyEmulator.switchOne][1]:
  193. iconPath = self.__icon['switch'][0]
  194. else:
  195. iconPath = self.__icon['switch'][1]
  196. self.__ui.buttonSwitchOne.setIcon(self.setupSwitchIcon(iconPath))
  197. if keys[self.__wsc.keyEmulator.switchTwo][1]:
  198. iconPath = self.__icon['switch'][2]
  199. else:
  200. iconPath = self.__icon['switch'][3]
  201. self.__ui.buttonSwitchTwo.setIcon(self.setupSwitchIcon(iconPath))
  202. if keys[self.__wsc.keyEmulator.switchAdaptive][1]:
  203. iconPath = self.__icon['switch'][4]
  204. else:
  205. iconPath = self.__icon['switch'][5]
  206. self.__ui.buttonSwitchAdaptive.setIcon(self.setupSwitchIcon(iconPath))
  207. def testKeys(self):
  208. time.sleep(3)
  209. for payload in [1, 0, 2, 0, 4, 0]:
  210. self.__wsc.keyEmulator.emulateKey(self.__strModuleID, payload)
  211. time.sleep(0.1)
  212. class IdeasXMainWindow(QtWidgets.QMainWindow):
  213. def __init__(self):
  214. super(IdeasXMainWindow, self).__init__()
  215. self.__ui = Ui_MainWindow()
  216. self.__ui.setupUi(self)
  217. p = self.__ui.contentEncoder.palette()
  218. p.setColor(self.backgroundRole(), QtCore.Qt.white)
  219. self.__ui.contentEncoder.setPalette(p)
  220. def setEncoderLayout(self, layout):
  221. self.__ui.contentEncoder.setLayout(layout)
  222. def setStatusBarMessage(self, msg):
  223. status = QtWidgets.QLabel()
  224. status.setText(msg)
  225. status.setAlignment(QtCore.Qt.AlignLeft)
  226. #status.setAlignment(QtCore.Qt.AlignLeft)
  227. self.__ui.statusbar.addWidget(status, 1) # IDK what the 1 does...I need to look it up
  228. def setStatusBarUpdate(self, msg):
  229. self.__ui.statusbar.showMessage(msg)
  230. if __name__ == "__main__":
  231. app = QtWidgets.QApplication(sys.argv)
  232. app.setWindowIcon(QtGui.QIcon('icon/logo/ideasx.png'))
  233. mainWindow = IdeasXMainWindow()
  234. wsc = IdeasXWSCNetworkThread()
  235. encoderManager = IdeasXDeviceManager(IdeasXEncoder, wsc)
  236. mainWindow.setEncoderLayout(encoderManager.returnLayout())
  237. wsc.encoderUpdate.connect(encoderManager.refreshDevices)
  238. wsc.networkStatus.connect(mainWindow.setStatusBarMessage)
  239. wsc.networkUpdate.connect(mainWindow.setStatusBarUpdate)
  240. wsc.guiStartWorkstationClient('ideasx.duckdns.org')
  241. #timer = QtCore.QTimer()
  242. #timer.timeout.connect(mainWindow.hideEncoder)
  243. #timer.start(1000)
  244. #time.sleep(0.5)
  245. mainWindow.show()
  246. sys.exit(app.exec_())