def __init__(self, rpi_hw=True):
        """rpi_hw should be True if running on actual HW"""
        if not rpi_hw:
            from mock import Mock

            global w1temp
            w1temp = Mock()
            w1temp.getTempF.return_value = 80
            print("Mocking w1temp")
            print("w1temp.getTempF returns {0}".format(w1temp.getTempF()))
        FORMAT = "%(asctime)s %(funcName)s:%(thread)d [%(levelname)s] %(message)s"
        logging.basicConfig(format=FORMAT, level=logging.INFO)
        self.ideal_temp = DEF_IDEAL_TEMP
        self.full_open_temp_diff = DEF_FULL_OPEN_TEMP_DIFF

        self.wx_station = "KBFI"
        # sleep interval is when window holds a position
        self.close_sleep_hour = 0
        self.close_sleep_minute = 0
        self.open_sleep_hour = 10
        self.open_sleep_minute = 45
        self.sleep_time_ratio = DEF_SLEEP_TIME_RATIO

        # close time is when the window closes regardless of temp
        self.close_hour = 5
        self.close_minute = 15
        # open time is when window returns to automatic mode
        self.open_hour = 9
        self.open_minute = 55

        self.window_driver = WindowDriver(STEP_RANGE)
        self.last_inside_temp = self._getInsideTemp()
class WindowAutoBot(object):
    def __init__(self, rpi_hw=True):
        """rpi_hw should be True if running on actual HW"""
        if not rpi_hw:
            from mock import Mock

            global w1temp
            w1temp = Mock()
            w1temp.getTempF.return_value = 80
            print("Mocking w1temp")
            print("w1temp.getTempF returns {0}".format(w1temp.getTempF()))
        FORMAT = "%(asctime)s %(funcName)s:%(thread)d [%(levelname)s] %(message)s"
        logging.basicConfig(format=FORMAT, level=logging.INFO)
        self.ideal_temp = DEF_IDEAL_TEMP
        self.full_open_temp_diff = DEF_FULL_OPEN_TEMP_DIFF

        self.wx_station = "KBFI"
        # sleep interval is when window holds a position
        self.close_sleep_hour = 0
        self.close_sleep_minute = 0
        self.open_sleep_hour = 10
        self.open_sleep_minute = 45
        self.sleep_time_ratio = DEF_SLEEP_TIME_RATIO

        # close time is when the window closes regardless of temp
        self.close_hour = 5
        self.close_minute = 15
        # open time is when window returns to automatic mode
        self.open_hour = 9
        self.open_minute = 55

        self.window_driver = WindowDriver(STEP_RANGE)
        self.last_inside_temp = self._getInsideTemp()

    def _getOverride(self):
        override = False
        try:
            f = open(windowOverrideFile, "r")
            ratio = int(f.readline().strip())
            endtime = int(f.readline().strip())
        except:
            logging.warning("getOverrride: unable to open override file: %s" % windowOverrideFile)
            f = open(windowOverrideFile, "w")
            f.write("0\n0\n")
            f.close()
            return (0, 0)
        f.close()
        curtime = int(time.time())
        logging.info("getOverride: endTime=%s curTime=%s diff=%s" % (endtime, curtime, endtime - curtime))
        if curtime < endtime:
            override = True
        return (override, ratio, endtime)

    def _isClosedTime(self):
        now = datetime.datetime.now()
        if now.hour > self.close_hour or (now.hour == self.close_hour and now.minute >= self.close_minute):
            if now.hour < self.open_hour or (now.hour == self.open_hour and now.minute < self.open_minute):
                return True
        return False

    def _isSleepTime(self):
        now = datetime.datetime.now()
        if now.hour > self.close_sleep_hour or (
            now.hour == self.close_sleep_hour and now.minute >= self.close_sleep_minute
        ):
            if now.hour < self.open_sleep_hour or (
                now.hour == self.open_sleep_hour and now.minute < self.open_sleep_minute
            ):
                return True
        return False

    def _getInsideTemp(self):
        w1temp.initialize1w()
        tempF = w1temp.getTempF()
        self.last_inside_temp = tempF
        return tempF

    def _getOutsideTemp(self):
        obsdict = noaaweather.get_wx(self.wx_station)
        temp_string = obsdict["temperature_string"].split(" ")[0]
        logging.info("getOutsideTemp: temp_string=%s" % temp_string)
        return float(temp_string)

    def _isOutsideWarm(self):
        try:
            outside_temp = self._getOutsideTemp()
            if outside_temp > self.ideal_temp:
                logging.info(
                    "isOutSideWarm: outside_temp %s exceeds ideal_temp %s,"
                    " returning TRUE" % (outside_temp, self.ideal_temp)
                )
                return True
            logging.info(
                "isOutSideWarm: outside_temp %s does not exceed ideal_temp %s,"
                " returning FALSE" % (outside_temp, self.ideal_temp)
            )
            return False
        except Exception as err:
            # Catch eveything as it's better to carry on execution if the wx
            # check fails.
            logging.info("Exception checking noaa wx: {0}".format(err.message))
            return False

    def _getOpenRatioByTemp(self):
        temp = self._getInsideTemp()
        open_ratio = (temp - self.ideal_temp) / self.full_open_temp_diff
        if open_ratio > 1:
            open_ratio = 1
        if open_ratio < 0:
            open_ratio = 0
        logging.info("getOpenRatioByTemp: temp=%s ideal_temp=%s open_ratio=%s" % (temp, self.ideal_temp, open_ratio))
        return open_ratio

    def get_inside_temp(self):
        return self.last_inside_temp

    def auto_window(self):
        (overrideActive, overrideRatio, overrideEnd) = self._getOverride()
        if overrideActive:
            open_percent = overrideRatio
        else:
            ideal_open_ratio = self._getOpenRatioByTemp()
            if self._isSleepTime():
                ideal_open_ratio = self.sleep_time_ratio
            if self._isClosedTime():
                ideal_open_ratio = 0
            if self._isOutsideWarm():
                ideal_open_ratio = 0
            open_percent = ideal_open_ratio * 100
        # move window
        self.window_driver.set_position(open_percent)

    def set_override(self, position, time):
        f = open(windowOverrideFile, "w")
        f.write(str(int(position)) + "\n")
        f.write(str(int(time)) + "\n")
        f.flush()
        f.close()
        self.auto_window()

    def get_override(self):
        return self._getOverride()

    def get_ideal_temp(self):
        return self.ideal_temp

    def set_ideal_temp(self, ideal_temp):
        self.ideal_temp = ideal_temp
        self.auto_window()

    def get_commanded_position(self):
        return self.window_driver.get_commanded_position()

    def get_actual_position(self):
        return self.window_driver.get_actual_position()