def __init__(self, parent=None):
        super(TempController, self).__init__(parent)
        self.ui = Ui_TempController()
        self.ui.setupUi(self)

        self.tempChart = MyMplCanvas(self.ui.tempTab, 10, 10, "Temperature reading (°C)")
        self.ui.verticalLayout_2.addWidget(self.tempChart)

        self.humidityChart = MyMplCanvas(self.ui.humidityTab, 10, 10, "Humidity reading (% humidity)")
        self.ui.verticalLayout_5.addWidget(self.humidityChart)

        self.serialManager = SerialManager(self.updateTempChart, self.updateHumChart)

        self.requestDataTimer = QtCore.QTimer()
        self.requestDataTimer.timeout.connect(self.requestData)

        self.connect_signals()

        self.tempData = []
        self.tempTimes = []
        self.humidityData = []
        self.humidityTimes = []

        self.humAlert = False
        self.tempAlert = False
        self.coolingOff = False
        self.alertHum = float('Inf')
        self.turnOffHum = float('Inf')
        self.setTemp = 2.5
        self.alertTemp = float('Inf')
class TempController(QWidget):
    def __init__(self, parent=None):
        super(TempController, self).__init__(parent)
        self.ui = Ui_TempController()
        self.ui.setupUi(self)

        self.tempChart = MyMplCanvas(self.ui.tempTab, 10, 10, "Temperature reading (°C)")
        self.ui.verticalLayout_2.addWidget(self.tempChart)

        self.humidityChart = MyMplCanvas(self.ui.humidityTab, 10, 10, "Humidity reading (% humidity)")
        self.ui.verticalLayout_5.addWidget(self.humidityChart)

        self.serialManager = SerialManager(self.updateTempChart, self.updateHumChart)

        self.requestDataTimer = QtCore.QTimer()
        self.requestDataTimer.timeout.connect(self.requestData)

        self.connect_signals()

        self.tempData = []
        self.tempTimes = []
        self.humidityData = []
        self.humidityTimes = []

        self.humAlert = False
        self.tempAlert = False
        self.coolingOff = False
        self.alertHum = float('Inf')
        self.turnOffHum = float('Inf')
        self.setTemp = 2.5
        self.alertTemp = float('Inf')

    @pyqtSlot()
    def set_warning_temp(self):
        self.alertTemp = self.ui.tempToleranceSpinBox.value()
        print("Alert Temperature:", self.alertTemp)

    @pyqtSlot()
    def set_temperature(self):
        self.coolingOff = False
        self.setTemp = self.ui.tempSpinBox.value()
        self.serialManager.setTemp(self.setTemp)
        print("Temperature:", self.setTemp)

    @pyqtSlot()
    def set_warning_humidity(self):
        self.alertHum = self.ui.warningThresholdSpinBox.value()
        print("Alert Humidity:", self.alertHum)

    @pyqtSlot()
    def set_turn_off_humidity(self):
        self.turnOffHum = self.ui.turnOffThresholdSpinBox.value()
        print("Turn off Humidity:", self.turnOffHum)

    @pyqtSlot()
    def connect_to_arduino(self):
        self.ui.connectButton.disconnect()
        self.ui.connectButton.clicked.connect(self.disconnect_from_arduino)
        self.ui.connectButton.setText("Disconnect")
        self.ui.ConnectField.setDisabled(True)
        serialLocation = self.ui.ConnectField.text()
        if not serialLocation:
            serialLocation = "/dev/ttyUSB0"
        print("Connect to:", serialLocation)
        self.serialManager.connect(serialLocation)
        self.requestData()
        self.requestDataTimer.start(15000)

    @pyqtSlot()
    def disconnect_from_arduino(self):
        self.requestDataTimer.stop()
        if(self.serialManager):
            self.serialManager.endSerial()
        self.ui.connectButton.disconnect()
        self.ui.connectButton.clicked.connect(self.connect_to_arduino)
        self.ui.connectButton.setText("Connect")
        self.ui.ConnectField.setDisabled(False)

    @pyqtSlot()
    def exportTempData(self):
        exportLocation = self.ui.tempExportField.text()
        if not exportLocation:
            exportLocation = "tempData.csv"
        self.exportData(self.tempTimes, self.tempData, exportLocation)

    @pyqtSlot()
    def exportHumidityData(self):
        exportLocation = self.ui.humidityExportField.text()
        if not exportLocation:
            exportLocation = "humidityData.csv"
        self.exportData(self.humidityTimes, self.humidityData, exportLocation)

    def exportData(self, times, data, exportLocation):
        print("exporting to:", exportLocation)
        with open(exportLocation, 'wb') as csvfile:
            writer = csv.writer(csvfile, delimiter=',')
            writer.writerow(times)
            writer.writerow(data)

    @pyqtSlot()
    def requestData(self):
        self.serialManager.writeLine("get data")

    @pyqtSlot()
    def addEmail(self):
        email = self.ui.addEmailField.text()
        self.ui.addEmailField.setText("")
        self.ui.emailList.addItem(email)

    @pyqtSlot()
    def deleteEmail(self):
        listItems=self.ui.emailList.selectedItems()
        for item in listItems:
            self.ui.emailList.takeItem(self.ui.emailList.row(item))

    def connect_signals(self):
        self.ui.tempSetButton.clicked.connect(self.set_temperature)
        self.ui.tempWarningButton.clicked.connect(self.set_warning_temp)
        self.ui.humidityWarningButton.clicked.connect(self.set_warning_humidity)
        self.ui.turnOffThresholdButton.clicked.connect(self.set_turn_off_humidity)
        self.ui.connectButton.clicked.connect(self.connect_to_arduino)
        self.ui.addEmailButton.clicked.connect(self.addEmail)
        self.ui.removeEmailButton.clicked.connect(self.deleteEmail)
        self.ui.tempExportButton.clicked.connect(self.exportTempData)
        self.ui.humidityExportButton.clicked.connect(self.exportHumidityData)

    def updateTempChart(self, data):
        x = list(self.perdelta(datetime.today(), datetime.today() - timedelta(minutes=(len(data))), timedelta(minutes=1)))
        times = matplotlib.dates.date2num(x)
        self.tempTimes = [time.strftime("%x %X") for time in x]
        self.tempData = data
        self.tempChart.graphData(times, data)
        if (data[0] > self.setTemp + self.alertTemp or data[0] < self.setTemp - self.alertTemp) and not self.tempAlert:
            listItems = list(map(lambda it: it.text(), self.ui.emailList.findItems("", QtCore.Qt.MatchContains)))
            self.sendTempAlert(listItems)

    def updateHumChart(self, data):
        x = list(self.perdelta(datetime.today(), datetime.today() - timedelta(minutes=(len(data))), timedelta(minutes=1)))
        times = matplotlib.dates.date2num(x)
        self.humidityTimes = [time.strftime("%x %X") for time in x]
        self.humidityData = data
        self.humidityChart.graphData(times, data)
        if data[0] > self.alertHum and not self.humAlert:
            listItems = list(map(lambda it: it.text(), self.ui.emailList.findItems("", QtCore.Qt.MatchContains)))
            self.sendHumAlert(listItems)
        if data[0] > self.turnOffHum and not self.coolingOff:
            listItems = list(map(lambda it: it.text(), self.ui.emailList.findItems("", QtCore.Qt.MatchContains)))
            self.turnCoolingOff(listItems)

    def sendTempAlert(self, listItems):
        self.tempAlert = True
        print("Temperature out of range")
        self.send_email_to_all(listItems, "MIST ALERT: Laser temperature out of range", "Please check the laser as soon as possible. " +
        "The laser temperature is outside of the specified range.")
        self.createMessageBox("Temperature out of range", self.setTempAlertFalse)

    def sendHumAlert(self, listItems):
        self.humAlert = True
        print("humidity warning")
        self.send_email_to_all(listItems, "MIST ALERT: Laser humidity too high", "Please check the laser as soon as possible. " +
        "The laser has reached its warning humidity and cooling will shut off soon.")
        self.createMessageBox("Humidity too high. Cooler will be turned off soon!", self.setHumAlertFalse)

    def turnCoolingOff(self, listItems):
        self.coolingOff = True
        print("Turning off cooling!")
        self.ui.tempSpinBox.setValue(5)
        self.set_turn_off_humidity()
        self.send_email_to_all(listItems, "MIST ALERT: Laser cooling turned off!", "Please check the laser as soon as possible. " +
        "The laser has reached its maximum humidity and cooling has been shut off.")
        self.createMessageBox("Humidity too high.  Cooler has been turned off!", None)

    def createMessageBox(self, msg, func):
        reply = QMessageBox(self)
        reply.setAttribute(QtCore.Qt.WA_DeleteOnClose)
        reply.setStandardButtons(QMessageBox.Ok)
        reply.setWindowTitle("Warning")
        reply.setIcon(QMessageBox.Warning)
        reply.setText(msg);
        reply.setModal(False);
        if func != None:
            reply.destroyed.connect(func)
        reply.show()
        return reply

    @pyqtSlot()
    def setTempAlertFalse(self):
        self.tempAlert = False

    @pyqtSlot()
    def setHumAlertFalse(self):
        self.humAlert = False

    def closeEvent(self, event):
        if(self.serialManager):
            self.serialManager.endSerial()

    def perdelta(self, start, end, delta):
        curr = start
        while curr > end:
            yield curr
            curr -= delta

    def send_email_to_all(self, listItems, subject, body):
        for item in listItems:
            print(item)
            self.send_email(item, subject, body)

    def send_email(self, recipient, subject, body):
        import smtplib

        gmail_user = '******'
        gmail_pwd = 'Yb171+Yb171+'
        FROM = gmail_user
        TO = recipient if type(recipient) is list else [recipient]
        SUBJECT = subject
        TEXT = body

        # Prepare actual message
        message = """\From: %s\nTo: %s\nSubject: %s\n\n%s
        """ % (FROM, ", ".join(TO), SUBJECT, TEXT)
        try:
            server = smtplib.SMTP("smtp.gmail.com", 587)
            server.ehlo()
            server.starttls()
            server.login(gmail_user, gmail_pwd)
            server.sendmail(FROM, TO, message)
            server.close()
            print('successfully sent email')
        except Exception as e:
            print( "Error failed to send email: %s" % str(e) )