globalwidgets.py 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. #
  2. # Moisture control - Global status/configuration widgets
  3. #
  4. # Copyright (c) 2013 Michael Buesch <m@bues.ch>
  5. #
  6. # This program is free software; you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation; either version 2 of the License, or
  9. # (at your option) any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License along
  17. # with this program; if not, write to the Free Software Foundation, Inc.,
  18. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  19. #
  20. from pymoistcontrol.util import *
  21. from pymoistcontrol.potwidgets import *
  22. from pymoistcontrol.adcwidgets import *
  23. from pymoistcontrol.dayofweek import *
  24. from pymoistcontrol.bitindicator import *
  25. class GlobalConfigWidget(QWidget):
  26. """Global configuration widget."""
  27. # Signal: Emitted, if a configuration item changed.
  28. configChanged = Signal()
  29. # Signal: Emitted, if the RTC date or time was edited.
  30. rtcEdited = Signal()
  31. def __init__(self, parent):
  32. """Class constructor."""
  33. QWidget.__init__(self, parent)
  34. self.setLayout(QGridLayout(self))
  35. y = 0
  36. self.__shouldCheckRtc = True
  37. self.enableCheckBox = QCheckBox("Enable the regulator globally",
  38. self)
  39. self.layout().addWidget(self.enableCheckBox, y, 0, 1, 2)
  40. y += 1
  41. self.watchdogWarning = QLabel()
  42. palette = self.watchdogWarning.palette()
  43. palette.setColor(QPalette.WindowText, QColor(255, 0, 0))
  44. self.watchdogWarning.setPalette(palette)
  45. self.watchdogWarning.hide()
  46. self.watchdogWarningPotNumbers = []
  47. self.layout().addWidget(self.watchdogWarning, y, 0, 1, 2)
  48. y += 1
  49. label = QLabel("RTC time:", self)
  50. self.layout().addWidget(label, y, 0)
  51. hbox = QHBoxLayout()
  52. self.rtcEdit = QDateTimeEdit(self)
  53. self.rtcEdit.setDisplayFormat("yyyy.MM.dd hh:mm:ss")
  54. self.rtcEdit.setReadOnly(True)
  55. hbox.addWidget(self.rtcEdit)
  56. self.rtcEditCheckBox = QCheckBox("edit", self)
  57. hbox.addWidget(self.rtcEditCheckBox)
  58. self.layout().addLayout(hbox, y, 1)
  59. y += 1
  60. self.statWidgets = []
  61. for i in range(MAX_NR_FLOWERPOTS):
  62. label = QLabel("Pot %d:" % (i + 1), self)
  63. self.layout().addWidget(label, y, 0)
  64. potStatWidget = PotShortStatusWidget(i, self)
  65. self.statWidgets.append(potStatWidget)
  66. self.layout().addWidget(potStatWidget, y, 1)
  67. y += 1
  68. self.stateLabel = QLabel(self)
  69. self.layout().addWidget(self.stateLabel, y, 0, 1, 2)
  70. y += 1
  71. self.advancedCheckBox = QCheckBox("Advanced", self)
  72. self.layout().addWidget(self.advancedCheckBox, y, 0, 1, 2)
  73. y += 1
  74. self.advancedGroup = QGroupBox(self)
  75. self.advancedGroup.setLayout(QGridLayout())
  76. self.layout().addWidget(self.advancedGroup, y, 0, 1, 2)
  77. y += 1
  78. label = QLabel("Lowest possible ADC value:", self)
  79. self.advancedGroup.layout().addWidget(label, 0, 0)
  80. self.lowestSensorSpin = ADCSpinBox(self)
  81. self.advancedGroup.layout().addWidget(self.lowestSensorSpin, 0, 1)
  82. label = QLabel("Highest possible ADC value:", self)
  83. self.advancedGroup.layout().addWidget(label, 1, 0)
  84. self.highestSensorSpin = ADCSpinBox(self)
  85. self.advancedGroup.layout().addWidget(self.highestSensorSpin, 1, 1)
  86. self.ignoreChanges = 0
  87. self.enableCheckBox.stateChanged.connect(self.__enableChanged)
  88. self.rtcEditCheckBox.stateChanged.connect(self.__rtcEditChanged)
  89. self.advancedCheckBox.stateChanged.connect(self.__advancedChanged)
  90. self.lowestSensorSpin.valueChanged.connect(self.__lowestSensorChanged)
  91. self.highestSensorSpin.valueChanged.connect(self.__highestSensorChanged)
  92. self.__advancedChanged(self.advancedCheckBox.checkState())
  93. def globalEnableActive(self):
  94. return self.enableCheckBox.checkState() == Qt.Checked
  95. def getRtcDateTime(self):
  96. return self.rtcEdit.dateTime()
  97. def lowestRawSensorVal(self):
  98. return self.lowestSensorSpin.value()
  99. def highestRawSensorVal(self):
  100. return self.highestSensorSpin.value()
  101. def __lowestSensorChanged(self, newValue):
  102. if not self.ignoreChanges:
  103. self.configChanged.emit()
  104. def __highestSensorChanged(self, newValue):
  105. if not self.ignoreChanges:
  106. self.configChanged.emit()
  107. def __advancedChanged(self, newState):
  108. if newState == Qt.Checked:
  109. self.advancedGroup.show()
  110. else:
  111. self.advancedGroup.hide()
  112. def __enableChanged(self, newState):
  113. if self.ignoreChanges:
  114. return
  115. if newState != Qt.Checked:
  116. res = QMessageBox.question(self,
  117. "Disable globally?",
  118. "Do you really want to disable the "
  119. "controller globally?\n"
  120. "Watering of all pots will be stopped.",
  121. QMessageBox.Yes | QMessageBox.No)
  122. if res != QMessageBox.Yes:
  123. self.enableCheckBox.setCheckState(Qt.Checked)
  124. return
  125. self.configChanged.emit()
  126. def __rtcEditChanged(self, newState):
  127. if newState == Qt.Checked:
  128. self.rtcEdit.setReadOnly(False)
  129. else:
  130. self.rtcEdited.emit()
  131. self.rtcEdit.setReadOnly(True)
  132. def handleGlobalConfMessage(self, msg):
  133. self.ignoreChanges += 1
  134. if msg.flags & msg.CONTR_FLG_ENABLE:
  135. self.enableCheckBox.setCheckState(Qt.Checked)
  136. else:
  137. self.enableCheckBox.setCheckState(Qt.Unchecked)
  138. self.lowestSensorSpin.setValue(msg.sensor_lowest_value)
  139. self.highestSensorSpin.setValue(msg.sensor_highest_value)
  140. self.__shouldCheckRtc = True
  141. self.ignoreChanges -= 1
  142. def handleGlobalStateMessage(self, msg):
  143. text = []
  144. if msg.flags & msg.CONTRSTAT_ONOFFSWITCH:
  145. text.append("Hardware switch is on")
  146. else:
  147. text.append("Hardware switch is OFF")
  148. if msg.flags & msg.CONTRSTAT_NOTIFLED:
  149. text.append("Notification LED is ON")
  150. self.stateLabel.setText("; ".join(text))
  151. def handlePotStateMessage(self, msg):
  152. self.ignoreChanges += 1
  153. self.statWidgets[msg.pot_number].handlePotStateMessage(msg)
  154. self.ignoreChanges -= 1
  155. def __updateWatchdogWarning(self):
  156. if self.watchdogWarningPotNumbers:
  157. self.watchdogWarning.setText(
  158. "WARNING: The watering watchdog was triggered.\n"\
  159. "Watering is disabled on: %s" %\
  160. ", ".join("pot %d" % (n + 1) for n in self.watchdogWarningPotNumbers))
  161. self.watchdogWarning.show()
  162. else:
  163. self.watchdogWarning.setText("")
  164. self.watchdogWarning.hide()
  165. def handlePotRemStateMessage(self, msg):
  166. self.ignoreChanges += 1
  167. if msg.flags & msg.POT_REMFLG_WDTRIGGER:
  168. if msg.pot_number not in self.watchdogWarningPotNumbers:
  169. self.watchdogWarningPotNumbers.append(msg.pot_number)
  170. self.__updateWatchdogWarning()
  171. else:
  172. if msg.pot_number in self.watchdogWarningPotNumbers:
  173. self.watchdogWarningPotNumbers.remove(msg.pot_number)
  174. self.__updateWatchdogWarning()
  175. self.ignoreChanges -= 1
  176. def handlePotConfMessage(self, msg):
  177. self.ignoreChanges += 1
  178. self.statWidgets[msg.pot_number].enableMessageHandling(msg.flags & msg.POT_FLG_ENABLED)
  179. self.ignoreChanges -= 1
  180. def handlePotEnableChange(self, potNumber, enabled):
  181. self.statWidgets[potNumber].enableMessageHandling(enabled)
  182. def __syncRtc(self):
  183. # Sync RTC with PC clock.
  184. self.rtcEditCheckBox.setCheckState(Qt.Unchecked)
  185. self.rtcEdit.setDateTime(QDateTime.currentDateTime())
  186. self.rtcEdited.emit()
  187. def handleRtcMessage(self, msg):
  188. self.ignoreChanges += 1
  189. date = QDate(2000 + msg.year, msg.month + 1, msg.day + 1)
  190. time = QTime(msg.hour, msg.minute, msg.second)
  191. dateTime = QDateTime(date, time)
  192. if self.rtcEdit.isReadOnly():
  193. self.rtcEdit.setDateTime(dateTime)
  194. if self.__shouldCheckRtc:
  195. error = QDateTime.currentDateTime().secsTo(dateTime)
  196. if abs(error) > 30:
  197. res = QMessageBox.question(self,
  198. "Fix RTC time drift?",
  199. "The RTC is off by %d seconds.\n"
  200. "Do you want to synchronize the RTC "
  201. "with the PC's clock?" % error,
  202. QMessageBox.Yes | QMessageBox.No,
  203. QMessageBox.Yes)
  204. if res == QMessageBox.Yes:
  205. self.__syncRtc()
  206. self.__shouldCheckRtc = False
  207. self.ignoreChanges -= 1