Beispiel #1
0
    def update_ignores_2sit(self):
        """
        Update open window variables according to weather
        :return: nothing
        """
        self.var.situation = weather.weather_for_woeid(
            self.setup.yahoo_location, self.setup.owm_location,
            self.setup.owm_api_key)
        if None not in self.var.situation.viewvalues():
            temp = int(self.var.situation["current_temp"])
            if temp is not None:
                # modify OWW
                # interval for oww 5min to 360min
                tmr = weather.interval_scale(temp, (-35.0, 35.0), (0, 10),
                                             (5, 360), True)
                self.setup.intervals["oww"] = [
                    tmr * 60, (3 * tmr) * 60, (3 * tmr) * 60
                ]
                logmsg.update("OWW interval updated to " +
                              str(self.setup.intervals["oww"]))

                # and now modify valve ignore time
                # interval for valve ignore 20min to 120min
                tmr = weather.interval_scale(temp, (0.0, 35.0), (1.7, 3.0),
                                             (20, 120), False)
                self.eq3.ignore_time = self.setup.window_ignore_time + tmr
                bridge.put("ign_op", self.eq3.ignore_time)
                logmsg.update(
                    "Valve ignore interval updated to " +
                    str(self.eq3.ignore_time), 'D')
Beispiel #2
0
 def open(self):
     if self.is_init():
         raise NameError("Wrong init!")
     if os.path.exists(self.file):
         try:
             os.rename(
                 self.file, self.place + self.dev_name + "_" +
                 time.strftime("%Y%m%d-%H%M%S", time.localtime()) + ".csv")
         except Exception:
             pass
     try:
         self.handle = open(self.file, "a")
     except IOError:
         this_path = os.path.dirname(self.file)
         if not os.path.exists(this_path):
             try:
                 os.makedirs(this_path)
             except Exception:
                 logmsg.update("Can't create directory for CSV files (" +
                               str(this_path) + ")")
                 raise
     except Exception:
         logmsg.update("Can't open CSV file: " + str(self.file))
         raise
     else:
         self.state = True
Beispiel #3
0
    def process_windows(self, ow):
        """
        Process dictionary and set ventilation status, then update owl web file
        :param ow: dictionary, open windows
        :return: nothing
        """
        # if count of open windows >= number of windows, that mean ventilation
        if len(ow) >= self.setup.ventilate_num:
            self.var.ventilating = True
        else:
            self.var.ventilating = False

        # write second web file

        secweb.write("owl", ow)
        # write bridge value
        bridge.put("owl", ow)
        # if open window warning is on and open window(s) count < number of open windows, that mean ventilation
        # send warnings for these windows
        if not self.setup.no_oww and len(ow) < self.setup.ventilate_num:
            for k, v in ow.iteritems():
                if self._is_win_open_too_long(k):
                    logmsg.update("Warning condition for window " + str(k) +
                                  " met")
                    self.send_warning("window", k, "")
Beispiel #4
0
    def control(self):
        self.check_var()
        open_windows = self.get_open_windows()

        # process open windows
        self.process_windows(open_windows)

        # and now showtime
        # heat: 0 = disable, 1 = heat per, 2 = total, 3 = svpnmw
        # heat, grt, heat_valve = self.heat_or_not_room()
        heat, grt, heat_valve = self.heat_or_not()

        # increment number of readings with heat on
        if bool(heat):
            self.var.heat_readings += 1

        if bool(heat) != self.var.heating:
            mode = bridge.try_read("mode").upper() == "AUTO"
            logmsg.debug("mode=", mode,
                         ", heat=", heat,
                         ", bool(heat)=", bool(heat))
            if heat > 0:
                logmsg.update(self.get_heat_string(heat, heat_valve, grt), 'I')
            else:
                logmsg.update("heating stopped.", 'I')
            if mode:
                self._do_heat(bool(heat))
Beispiel #5
0
    def control(self):
        self.check_var()
        open_windows = self.get_open_windows()

        # process open windows
        self.process_windows(open_windows)

        # and now showtime
        # heat: 0 = disable, 1 = heat per, 2 = total, 3 = svpnmw
        # heat, grt, heat_valve = self.heat_or_not_room()
        heat, grt, heat_valve = self.heat_or_not()

        # increment number of readings with heat on
        if bool(heat):
            self.var.heat_readings += 1

        if bool(heat) != self.var.heating:
            mode = bridge.try_read("mode").upper() == "AUTO"
            logmsg.debug("mode=", mode, ", heat=", heat, ", bool(heat)=",
                         bool(heat))
            if heat > 0:
                logmsg.update(self.get_heat_string(heat, heat_valve, grt), 'I')
            else:
                logmsg.update("heating stopped.", 'I')
            if mode:
                self._do_heat(bool(heat))
Beispiel #6
0
def check_day_table():
    global table
    if len(table.day) > 1:
        for i in range(len(table.day) - 1):
            if time.strptime(table.day[i + 1][0], "%H:%M") <= time.strptime(table.day[i][0], "%H:%M"):
                logmsg.update("Day mode table is wrong! Using default table!", 'E')
                table.day = [["00:00", "23:59", 40, 185, "total", 120, 1]]
Beispiel #7
0
def save_location(location):
    global sw
    try:
        f = open(sw.location["loc"], "w")
    except IOError:
        logmsg.update("IOError during opening location file for writing!", 'E')
    f.write(str({"location": str(location)}))
    f.close()
Beispiel #8
0
def save_location(location):
    global sw
    try:
        f = open(sw.location["loc"], "w")
    except IOError:
        logmsg.update("IOError during opening location file for writing!", 'E')
    f.write(str({"location":str(location)}))
    f.close()
Beispiel #9
0
def temp_mode():
    global table
    c_temp = int(table.sit["current_temp"])
    for k in table.temp:
        kv = table.temp[k]
        if kv[1] > c_temp >= kv[0]:
            table.act_mode_idx = k
            logmsg.update("Switching temp mode to " + str(kv[0]) + " ~ " + str(kv[1]), 'I')
            return kv
Beispiel #10
0
 def _mute(self, key):
     """
     Mute warning for windows key
     :param key: string
     :return: nothing
     """
     if key in self.eq3.windows:
         self.eq3.windows[key][0] = datetime.datetime.now()
         self.eq3.windows[key][1] = True
         logmsg.update("OWW for key " + str(key) + " is muted for " +
                       str(self.setup.intervals["oww"][2]) + " seconds.")
Beispiel #11
0
def time_mode():
    global table
    # day = [0-from_str, 1-to_str, 2-total or per, 3-mode ("total"/"per"), 4-check interval, 5-valves]
    md = is_time()
    # logmsg.update("Actual index=" + str(table.act_mode_idx), 'D')
    if md != -1:
        if md != table.act_mode_idx:
            kv = table.day[md]
            table.act_mode_idx = md
            logmsg.update("Switching day mode to " + str(md) + " = " + str(kv), 'I')
            return kv
Beispiel #12
0
 def _mute(self, key):
     """
     Mute warning for windows key
     :param key: string
     :return: nothing
     """
     if key in self.eq3.windows:
         self.eq3.windows[key][0] = datetime.datetime.now()
         self.eq3.windows[key][1] = True
         logmsg.update("OWW for key " + str(key) + " is muted for " + str(
             self.setup.intervals["oww"][2]) + " seconds.")
Beispiel #13
0
def check_day_table():
    """
    :return:
    """
    global table
    if len(table.day) > 1:
        for i in range(len(table.day) - 1):
            if time.strptime(table.day[i + 1][0], "%H:%M") <= time.strptime(
                    table.day[i][0], "%H:%M"):
                logmsg.update("Day mode table is wrong! Using default table!",
                              'E')
                table.day = [["00:00", "23:59", 35, 185, "total", 120, 2]]
Beispiel #14
0
 def _do_autoupdate(self):
     """
     Perform autoupdate
     :return: nothing
     """
     if autoupdate.do(self.setup.version):
         logmsg.update("thermeq3 updated.", 'I')
         temp_key = self.eq3.maxid["sn"]
         body = """<h1>Device upgrade information.</h1>
         <p>Hello, I'm your thermostat and I have a information for you.<br/>
         Please take a note, that I found new version of me and I'll be upgraded in few seconds.</br>
         Resistance is futile :).<br/>"""
         self.send_warning("upgrade", temp_key, body)
         self.queue_msg('R')
Beispiel #15
0
def send_email(eq3_setup, message):
    """
    sends email
    :param eq3_setup: thermeq3.setup
    :param message:
    :return: boolean, true if success
    """
    try:
        server = smtplib.SMTP(eq3_setup.mail_server, eq3_setup.mail_port)
    except Exception, error:
        logmsg.update("Error connecting to mail server " +
                      str(eq3_setup.mail_server) + ":" +
                      str(eq3_setup.mail_port) + ". Error code: " + str(error))
        logmsg.update("Traceback: " + str(traceback.format_exc()))
Beispiel #16
0
    def update_ignores_2sit(self):
        self.var.situation = weather.weather_for_woeid(self.setup.location)
        temp = int(self.var.situation["current_temp"])

        # modify OWW
        tmr = weather.interval_scale(temp, (-35.0, 35.0), (0, 10), (10, 360), True)
        self.setup.intervals["oww"] = [tmr * 60, (3 * tmr) * 60, (3 * tmr) * 60]
        logmsg.update("OWW interval updated to " + str(self.setup.intervals["oww"]))

        # and now modify valve ignore time
        tmr = weather.interval_scale(temp, (0.0, 35.0), (1.7, 3.0), (15, 120), False)
        self.var.ignore_time = self.setup.window_ignore_time + tmr
        bridge.put("ign_op", self.var.ignore_time)
        logmsg.update("Valve ignore interval updated to " + str(self.var.ignore_time), 'D')
Beispiel #17
0
def send_email(eq3_setup, message):
    """
    sends email
    :param eq3_setup: thermeq3.setup
    :param message:
    :return: boolean, true if success
    """
    try:
        server = smtplib.SMTP(eq3_setup.mail_server, eq3_setup.mail_port)
    except Exception, error:
        logmsg.update(
            "Error connecting to mail server " + str(eq3_setup.mail_server) + ":" + str(
                eq3_setup.mail_port) + ". Error code: " + str(error))
        logmsg.update("Traceback: " + str(traceback.format_exc()))
Beispiel #18
0
def weather_for_woeid(woeid, owm_id, owm_api_key):
    """
    Returns weather from yahoo weather from given WOEID
    :param owm_id:
    :param owm_api_key:
    :param woeid: integer, yahoo weather ID
    :return: dictionary, {"current_temp": temp, "city": city, "humidity": humidity}
    """
    city = "Error city"
    temp = None
    humidity = None

    if woeid is None or owm_id is None:
        logmsg.update("Wrong WOEID! Please set WOEID in config.py.", 'E')
    elif owm_api_key is None:
        logmsg.update("OWM API key not set!", 'E')
    else:
        # please change u='c' to u='f' for fahrenheit below
        base_url = "https://query.yahooapis.com/v1/public/yql?"
        yql_query = "select * from weather.forecast where woeid=" + str(
            woeid) + " and u='c'"
        yql_url = base_url + urllib.urlencode({'q': yql_query
                                               }) + "&format=json"

        try:
            result = urllib2.urlopen(yql_url).read()
            data = json.loads(result)
        except Exception, error:
            logmsg.update("Yahoo communication error: " + str(error), 'E')
            logmsg.update("Traceback: " + str(traceback.format_exc()), 'E')
        else:
Beispiel #19
0
def write(cw, message):
    """
    Save message to file which is in secondary web directory
    :param message: message or string to write to file
    :param cw: string, selector what to save
    """
    global sw
    if cw in sw.location:
        fn = sw.location[str(cw)]
        try:
            swf = open(fn, "w")
        except IOError as e:
            logmsg.update("Error opening file " + fn +
                          "! I/O error({0}): {1}".format(e.errno, e.strerror))
        except EnvironmentError:
            logmsg.update("Environment error while opening " + fn + "!", 'E')
        else:
            try:
                swf.write(str(message))
            except EnvironmentError:
                logmsg.update("Environment error while writing " + fn + "!",
                              'E')
            swf.close()
    else:
        logmsg.update("Wrong target [" + str(cw) + "] for saving file!", 'E')
Beispiel #20
0
def weather_for_woeid(woeid, owm_id, owm_api_key):
    """
    Returns weather from yahoo weather from given WOEID
    :param owm_id:
    :param owm_api_key:
    :param woeid: integer, yahoo weather ID
    :return: dictionary, {"current_temp": temp, "city": city, "humidity": humidity}
    """
    city = "Error city"
    temp = None
    humidity = None

    if woeid is None or owm_id is None:
        logmsg.update("Wrong WOEID! Please set WOEID in config.py.", 'E')
    elif owm_api_key is None:
        logmsg.update("OWM API key not set!", 'E')
    else:
        # please change u='c' to u='f' for fahrenheit below
        base_url = "https://query.yahooapis.com/v1/public/yql?"
        yql_query = "select * from weather.forecast where woeid=" + str(woeid) + " and u='c'"
        yql_url = base_url + urllib.urlencode({'q': yql_query}) + "&format=json"

        try:
            result = urllib2.urlopen(yql_url).read()
            data = json.loads(result)
        except Exception, error:
            logmsg.update("Yahoo communication error: " + str(error), 'E')
            logmsg.update("Traceback: " + str(traceback.format_exc()), 'E')
        else:
Beispiel #21
0
 def _do_autoupdate(self):
     """
     Perform autoupdate
     :return: nothing
     """
     if autoupdate.do(self.setup.version):
         logmsg.update("thermeq3 updated.", 'I')
         temp_key = self.eq3.maxid["sn"]
         body = """<h1>Device upgrade information.</h1>
         <p>Hello, I'm your thermostat and I have a information for you.<br/>
         Please take a note, that I found new version of me and I'll be upgraded in few seconds.</br>
         Resistance is futile :).<br/>"""
         self.send_warning("upgrade", temp_key, body)
         self.queue_msg('R')
Beispiel #22
0
 def check_var(self):
     """
     Check if variables are set correctly, reports any problem
     :return: nothing
     """
     if self.setup.valve_num > len(self.eq3.valves):
         logmsg.update("You have only " + str(len(self.eq3.valves)) +
                       " valves, but you want to " +
                       str(self.setup.valve_num) +
                       " of them be checked to turn on heating!")
         self.setup.valve_num = len(self.eq3.valves)
     if self.setup.valve_switch > 90:
         logmsg.update("Valve switch position over 90%!")
         self.setup.valve_switch = 90
     if self.setup.svpnmw > 100:
         logmsg.update(
             "Single valve switch position over 100%! Please check svpnmw variable!"
         )
     # uncomment below if you want auto correct value
     # self.setup.svpnmw = 100
     if self.setup.valve_switch > self.setup.svpnmw:
         logmsg.update("svpnmw (" + str(self.setup.svpnmw) +
                       "%) is less or equal to valve switch setup (" +
                       str(self.setup.valve_switch) + "%)!")
         self.setup.svpnmw = self.setup.valve_switch
Beispiel #23
0
def time_mode():
    """
    :return:
    """
    global table
    # day = [0-from_str, 1-to_str, 2-total or per, 3-mode ("total"/"per"), 4-check interval, 5-valves]
    md = is_time()
    # logmsg.update("Actual index=" + str(table.act_mode_idx), 'D')
    if md != -1:
        if md != table.act_mode_idx:
            kv = table.day[md]
            table.act_mode_idx = md
            logmsg.update("Switching day mode to " + str(md) + " = " + str(kv),
                          'I')
            return kv
Beispiel #24
0
 def _literal_process(self):
     for k, v in bridge.cw.iteritems():
         if v[2]:
             tmp = bridge.get(k)
             codeword = v[0]
             setvalue = v[1]
             try:
                 lit_result = literal_eval(tmp)
             except Exception:
                 logmsg.update("Bridge error codeword [" + str(codeword) + "] value [" + str(setvalue) + "]", 'D')
             else:
                 if codeword == bridge.rcw("ht"):
                     self.var.ht = lit_result
                 elif codeword == bridge.rcw("ign"):
                     self.eq3.ignored_valves = lit_result
Beispiel #25
0
 def get_ip(self):
     """
     Get IP and set variables
     :return: nothing
     """
     tmp = public_ip.get()
     if tmp == 0xFF:
         logmsg.update("Error getting IP address from hostname, please check resolv.conf or hosts or both!", 'E')
     else:
         self.setup.myip = tmp
         if public_ip.is_private(tmp):
             logstr = "Local"
         else:
             logstr = "Public"
         logmsg.update(logstr + " IP address: " + self.setup.myip)
Beispiel #26
0
def temp_mode():
    """
    :return:
    """
    global table
    if None not in table.sit.viewvalues():
        c_temp = int(table.sit["current_temp"])
        for k in range(0, len(table.temp)):
            kv = table.temp[k]
            if kv[1] > c_temp >= kv[0]:
                table.act_mode_idx = k
                logmsg.update("Switching temp mode to " + str(kv[0]) + " ~ " + str(kv[1]), 'I')
                return kv
    else:
        logmsg.update("Weather situation error", 'E')
Beispiel #27
0
 def adjust_ignored_valves(self, ow):
     """
     Adjust ignored valves, if window associated with ignored valve was opened too long, extend valve ignore time
     :param ow: dictionary, open windows
     :return: nothing
     """
     ow_now = self.get_open_windows()
     if not cmp(ow_now, ow) == 0:
         adj_list = set(ow) ^ set(ow_now)
         for a in adj_list:
             room = self.eq3.devices[a][3]
             for k, v in self.eq3.devices.iteritems():
                 # this is heating thermostat and is in room where we want ignore all heating thermostats
                 if v[0] == 1 and v[3] == room and k in self.eq3.ignored_valves:
                     tmp_time = self.eq3.ignored_valves[k]
                     self.eq3.ignored_valves.update({k: tmp_time + (1 * self.eq3.ignore_time) * 60})
                     logmsg.update("Valve: " + str(k) + " adjusted.")
Beispiel #28
0
 def write(self, cw, message):
     """
     saves txt to file which is in secondary web directory
     :param message: message/string to write to file
     :param cw: string, selector what to save
     """
     if cw in self.location:
         fn = self.location[str(cw)]
         try:
             swf = open(fn, "w")
         except Exception:
             logmsg.update("Error writing to file " + fn + "!", 'E')
         else:
             swf.write(str(message))
             swf.close()
     else:
         logmsg.update("Wrong target [" + str(cw) + "] for saving file!", 'E')
Beispiel #29
0
 def get_ip(self):
     """
     Get IP and set variables
     :return: nothing
     """
     tmp = public_ip.get()
     if tmp == 0xFF:
         logmsg.update(
             "Error getting IP address from hostname, please check resolv.conf or hosts or both!",
             'E')
     else:
         self.setup.my_ip = tmp
         if public_ip.is_private(tmp):
             log_str = "Local"
         else:
             log_str = "Public"
         logmsg.update(log_str + " IP address: " + self.setup.my_ip)
Beispiel #30
0
def temp_mode():
    """
    :return:
    """
    global table
    if None not in table.sit.viewvalues():
        c_temp = int(table.sit["current_temp"])
        for k in range(0, len(table.temp)):
            kv = table.temp[k]
            if kv[1] > c_temp >= kv[0]:
                table.act_mode_idx = k
                logmsg.update(
                    "Switching temp mode to " + str(kv[0]) + " ~ " +
                    str(kv[1]), 'I')
                return kv
    else:
        logmsg.update("Weather situation error", 'E')
Beispiel #31
0
    def close(self):
        try:
            self.handle.flush()
        except:
            pass

        try:
            os.fsync(self.handle.fileno())
        except:
            pass

        try:
            self.handle.close()
        except Exception:
            logmsg.update("Can't close CSV file!")
        else:
            self.state = False
Beispiel #32
0
def import_(config_str):
    """
    Import config_str into bridgeclient.json dictionary
    :param config_str: string/json
    :return: boolean
    """
    global bridgeclient
    result = False
    try:
        tmp = json.loads(config_str)
    except ValueError:
        logmsg.update("Error during importing JSON.", 'E')
    else:
        result = True
        bridgeclient.json.update(tmp)

    return result
Beispiel #33
0
def save(bridgefile):
    global bridgeclient, cw
    try:
        f = open(bridgefile, "w")
    except Exception:
        logmsg.update("Error writing to bridgefile!", 'E')
    else:
        for k, v in cw.iteritems():
            try:
                tmp = bridgeclient.get(v[0])
            except Exception:
                tmp = ""
            if tmp == "None" or tmp is None:
                tmp = str(v[1])
            f.write(v[0] + "=" + str(tmp) + "\r\n")
        f.close()
        return True
Beispiel #34
0
def send_email(m_id, message):
    """
    sends email
    :param m_id: dictionary
    :param message:
    :return:
    """
    m_server = m_id["sr"]
    m_port = m_id["p"]
    m_fromaddr = m_id["f"]
    m_frompwd = m_id["pw"]
    m_toaddr = m_id["t"]
    try:
        server = smtplib.SMTP(m_server, m_port)
    except Exception, error:
        logmsg.update(
            "Error connecting to mail server " + str(m_server) + ":" + str(m_port) + ". Error code: " + str(error))
        logmsg.update("Traceback: " + str(traceback.format_exc()))
Beispiel #35
0
 def _process_command(self):
     """
     Process command from cmd bridge
     :return: True if quit is received
     """
     cmd = bridge.get_cmd()
     if cmd == "quit":
         return True
     elif cmd[0:6] == "adjust":
         key = cmd[7:]
         if key in self.eq3.ignored_valves:
             del self.eq3.ignored_valves[key]
     elif cmd == "log_debug":
         logmsg.level('D')
     elif cmd == "log_info":
         logmsg.level('I')
     elif cmd[0:4] == "mute":
         self._mute(cmd[5:])
     elif cmd == "rebridge":
         br_data = bridge.load(self.setup.bridge_file)
         self._literal_process(br_data)
         self.update_all()
     elif cmd == "led":
         if self.var.heating:
             self.queue_msg("H")
         else:
             self.queue_msg("S")
     elif cmd == "upgrade":
         self._do_autoupdate()
     # add dummy room, valve, window, for testing, format: add:o = add open window, add:c = add closed window
     # add:r = remove
     elif cmd[0:4] == "dmy:":
         if cmd[4:5] == 'o':
             dummy.add_dummy(True)
         elif cmd[4:5] == 'c':
             dummy.add_dummy(False)
         elif cmd[4:5] == 'r':
             dummy.remove_dummy()
     elif cmd[0:7] == "del_dev:":
         tmp = str(cmd[8:])
         if self.eq3.delete(tmp):
             logmsg.update("Device " + tmp + " deleted successfully.", 'I')
         else:
             logmsg.update("Can't delete device " + tmp, 'I')
Beispiel #36
0
 def _process_command(self):
     """
     Process command from cmd bridge
     :return: True if quit is received
     """
     cmd = bridge.get_cmd()
     if cmd == "quit":
         return True
     elif cmd[0:6] == "adjust":
         key = cmd[7:]
         if key in self.eq3.ignored_valves:
             del self.eq3.ignored_valves[key]
     elif cmd == "log_debug":
         logmsg.level('D')
     elif cmd == "log_info":
         logmsg.level('I')
     elif cmd[0:4] == "mute":
         self._mute(cmd[5:])
     elif cmd == "rebridge":
         br_data = bridge.load(self.setup.bridge_file)
         self._literal_process(br_data)
         self.update_all()
     elif cmd == "led":
         if self.var.heating:
             self.queue_msg("H")
         else:
             self.queue_msg("S")
     elif cmd == "upgrade":
         self._do_autoupdate()
     # add dummy room, valve, window, for testing, format: add:o = add open window, add:c = add closed window
     # add:r = remove
     elif cmd[0:4] == "dmy:":
         if cmd[4:5] == 'o':
             dummy.add_dummy(True)
         elif cmd[4:5] == 'c':
             dummy.add_dummy(False)
         elif cmd[4:5] == 'r':
             dummy.remove_dummy()
     elif cmd[0:7] == "del_dev:":
         tmp = str(cmd[8:])
         if self.eq3.delete(tmp):
             logmsg.update("Device " + tmp + " deleted successfully.", 'I')
         else:
             logmsg.update("Can't delete device " + tmp, 'I')
Beispiel #37
0
def send_error_log(eq3_setup, stderr_log):
    """
    Send error log if any
    :param eq3_setup: thermeq3.setup
    :param stderr_log: string
    :return: -1 if no error log
    """
    if not (not os.path.isfile(stderr_log) or not (os.path.getsize(stderr_log) > 0)):
        subject = eq3_setup.device_name + " log email (thermeq3 device)"
        body = ("<h1>%(a0)s status email.</h1>\n"
                "<p>Hello, I'm your thermostat.<br/>"
                " I found this error log. It's attached.<br/>") % {"a0": str(eq3_setup.device_name)}
        msg = compose(eq3_setup, subject, body)
        msg.attach(attach_file(stderr_log))
        return send_email(eq3_setup, msg.as_string())
    else:
        logmsg.update("Logfile: " + stderr_log)
        logmsg.update("Zero sized stderr log file, nothing'll be send")
        return False
Beispiel #38
0
 def adjust_ignored_valves(self, ow):
     """
     Adjust ignored valves, if window associated with ignored valve was opened too long, extend valve ignore time
     :param ow: dictionary, open windows
     :return: nothing
     """
     ow_now = self.get_open_windows()
     if not cmp(ow_now, ow) == 0:
         adj_list = set(ow) ^ set(ow_now)
         for a in adj_list:
             room = self.eq3.devices[a][3]
             for k, v in self.eq3.devices.iteritems():
                 # this is heating thermostat and is in room where we want ignore all heating thermostats
                 if v[0] == 1 and v[
                         3] == room and k in self.eq3.ignored_valves:
                     tmp_time = self.eq3.ignored_valves[k]
                     self.eq3.ignored_valves.update(
                         {k: tmp_time + (1 * self.eq3.ignore_time) * 60})
                     logmsg.update("Valve: " + str(k) + " adjusted.")
Beispiel #39
0
def send_error_log(m_id, stderr_log, devname):
    """
    Send error log if any
    :param m_id: list
    :param stderr_log: string
    :param devname: string
    :return: -1 if no error log
    """
    if os.path.isfile(stderr_log) and os.path.getsize(stderr_log) > 0:
        body = ("<h1>%(a0)s status email.</h1>\n"
                "<p>Hello, I'm your thermostat and I sending you this email with error logfile as attachment.<br/>") \
               % {"a0": str(devname)}
        m_id.update({"s": m_id["d"] + " log email (thermeq3 device)"})
        msg = compose(m_id, body)
        msg.attach(attach_file(stderr_log))
        return send_email(m_id, msg.as_string())
    else:
        logmsg.update("Zero sized stderr log file, nothing'll be send")
        return False
Beispiel #40
0
    def silence(self, key, is_win):
        #
        # eq3.windows = key: OW_time(thisnow), is muted by user(False), warning/error count(0), multiplicand
        #
        # is there key in dict?
        dt = datetime.datetime.now()
        if key not in self.eq3.windows:
            # there no key, so its new warning
            logmsg.update("No key " + str(key) + " in windows. Key added.")
            if is_win:
                self.eq3.windows.update(
                    {key: [self.eq3.devices[key][5], False, 0, 1]})
            else:
                self.eq3.windows.update({key: [dt, False, 0, 1]})
            return 2
        else:
            # yes, there it is, so check if we are silent, if so exit, otherwise reset mute
            # threshold, send every X, muted for X
            # "oww": [10*60, 30*60, 45*60]
            # threshold, muted for X, time.time()
            # "wrn": [60*60, 60*60, tm]
            if self.eq3.windows[key][1]:
                # yes, we must be silent
                if is_win:
                    tmp = self.eq3.windows[key][0] + datetime.timedelta(
                        seconds=self.setup.intervals["oww"][2])
                else:
                    tmp = self.eq3.windows[key][0] + datetime.timedelta(
                        seconds=self.setup.intervals["wrn"][1])
                if tmp < dt:
                    return 1
                else:
                    # silence is over
                    self.eq3.windows[key][1] = False

        # increment warning counter for this key
        self.eq3.windows[key][2] += 1
        if self.eq3.windows[key][2] > self.setup.abnormalCount:
            logmsg.update("Abnormal #warnings for device [" + str(key) +
                          "], name [" + str(self.eq3.devices[key][2]) + "]")
            self.eq3.windows[key][2] = 0
        return 0
Beispiel #41
0
def weather_for_woeid(woeid):
    """
    Returns weather from yahoo weather from given WOEID
    :param woeid: integer, yahoo weather ID
    :return: dictonary, {"current_temp": temp, "city": city, "humidity": humidity}
    """
    # please change u='c' to u='f' for farenheit below
    baseurl = "https://query.yahooapis.com/v1/public/yql?"
    yql_query = "select * from weather.forecast where woeid=" + str(woeid) + " and u='c'"
    yql_url = baseurl + urllib.urlencode({'q': yql_query}) + "&format=json"

    try:
        result = urllib2.urlopen(yql_url).read()
        data = json.loads(result)
    except Exception, error:
        logmsg.update("Yahoo communication error: " + str(error), 'E')
        logmsg.update("Traceback: " + str(traceback.format_exc()), 'E')
        city = "Error city"
        temp = 0
        humidity = 50
Beispiel #42
0
 def export_csv(self, cmd="init"):
     csv_file = self.setup.csv_log
     if cmd == "init":
         if os.path.exists(csv_file):
             os.rename(csv_file,
                       self.setup.place + self.setup.devname + "_" + time.strftime("%Y%m%d-%H%M%S",
                                                                                   time.localtime()) + ".csv")
         try:
             self.var.csv = open(csv_file, "a")
         except Exception:
             logmsg.update("Can't open CSV file: " + str(csv_file))
             raise
         else:
             # headers here
             self.var.csv.write(self.eq3.headers())
             self.var.csv.write("\r\n")
     elif cmd == "close":
         try:
             self.var.csv.close()
         except Exception:
             logmsg.update("Can't close CSV file!")
Beispiel #43
0
 def _do_thermeq(self):
     """
     Do what thermeq must do
     :return: nothing
     """
     # save open window dictionary for adjustment
     ow = self.get_open_windows()
     eq3_result, eq3_error = self.eq3.read_data(False)
     if eq3_result:
         # set values
         self.get_control_values()
         # log messages
         logmsg.update(self._status_msg() + " Checking #" + str(self.setup.intervals["max"][0]) + " sec", 'I')
         logmsg.update(self.eq3.plain(), 'I')
         # do control
         self.control()
         # update JSONs
         self.write_strings()
         # set status
         self._set_status()
         # do logging
         self.do_device_logging()
         # do some valve_ignored adjustment
         self.adjust_ignored_valves(ow)
         # save bridge
         self.set_bridge_control_values()
         bridge.save(self.setup.bridge_file)
     else:
         self.var.heating = None
         if any("response" in e for e in eq3_error):
             self.queue_msg('M')
         else:
             self.queue_msg('E')
         # flush error to log
         logmsg.update("".join(str(e) + " " for e in eq3_error), 'E')
Beispiel #44
0
 def process_msg(self):
     """
     Process message queue
     :return: nothing
     """
     cw_msg = bridge.rcw("msg")
     while len(self.var.msgQ) > 0:
         logmsg.update("Message queue=" + str(self.var.msgQ), 'D')
         while not str(bridge.get(cw_msg)) == "":
             time.sleep(self.setup.timeout)
             tosend = self.var.msgQ.pop()
             logmsg.update("Sending message [" + str(tosend) + "]", 'D')
             if tosend == "E":
                 self.var.error = True
                 self.var.err2Clear = True
             elif tosend == "C":
                 self.var.err2Clear = False
                 self.var.err2LastStatus = True
                 logmsg.update("Clearing error LED", 'D')
             elif tosend == "R":
                 bridge.save(self.setup.bridgefile)
             if self.setup.target == "yun":
                 bridge.put(cw_msg, tosend)
             elif self.setup.target == "rpi":
                 if tosend == "H":
                     # action.do(True)
                     pass
                 elif tosend == "S":
                     # action.do(False)
                     pass
Beispiel #45
0
def send_error_log(eq3_setup, stderr_log):
    """
    Send error log if any
    :param eq3_setup: thermeq3.setup
    :param stderr_log: string
    :return: -1 if no error log
    """
    if not (not os.path.isfile(stderr_log)
            or not (os.path.getsize(stderr_log) > 0)):
        subject = eq3_setup.device_name + " log email (thermeq3 device)"
        body = ("<h1>%(a0)s status email.</h1>\n"
                "<p>Hello, I'm your thermostat.<br/>"
                " I found this error log. It's attached.<br/>") % {
                    "a0": str(eq3_setup.device_name)
                }
        msg = compose(eq3_setup, subject, body)
        msg.attach(attach_file(stderr_log))
        return send_email(eq3_setup, msg.as_string())
    else:
        logmsg.update("Logfile: " + stderr_log)
        logmsg.update("Zero sized stderr log file, nothing'll be send")
        return False
Beispiel #46
0
    def update_ignores_2sit(self):
        """
        Update open window variables according to weather
        :return: nothing
        """
        self.var.situation = weather.weather_for_woeid(self.setup.yahoo_location, self.setup.owm_location,
                                                       self.setup.owm_api_key)
        if None not in self.var.situation.viewvalues():
            temp = int(self.var.situation["current_temp"])
            if temp is not None:
                # modify OWW
                # interval for oww 5min to 360min
                tmr = weather.interval_scale(temp, (-35.0, 35.0), (0, 10), (5, 360), True)
                self.setup.intervals["oww"] = [tmr * 60, (3 * tmr) * 60, (3 * tmr) * 60]
                logmsg.update("OWW interval updated to " + str(self.setup.intervals["oww"]))

                # and now modify valve ignore time
                # interval for valve ignore 20min to 120min
                tmr = weather.interval_scale(temp, (0.0, 35.0), (1.7, 3.0), (20, 120), False)
                self.eq3.ignore_time = self.setup.window_ignore_time + tmr
                bridge.put("ign_op", self.eq3.ignore_time)
                logmsg.update("Valve ignore interval updated to " + str(self.eq3.ignore_time), 'D')
Beispiel #47
0
    def silence(self, key, is_win):
        #
        # d_w = key: OW_time(thisnow), isMuted(False), warning/error count(0)
        #
        # is there key in dict?
        dt = datetime.datetime.now()
        if key not in self.eq3.windows:
            # there no key, so its new warning
            logmsg.update("No key " + str(key) + " in windows. Key added.")
            if is_win:
                self.eq3.windows.update({key: [self.eq3.devices[key][5], False, 0]})
            else:
                self.eq3.windows.update({key: [dt, False, 0]})
            return 2
        else:
            # yes, there it is, so check if we are silent, if so exit, otherwise reset mute
            # threshold, send every X, muted for X
            # "oww": [10*60, 30*60, 45*60]
            # threshold, muted for X, time.time()
            # "wrn": [60*60, 60*60, tm]
            if self.eq3.windows[key][1]:
                # yes, we must be silent
                if is_win:
                    tmp = self.eq3.windows[key][0] + datetime.timedelta(seconds=self.setup.intervals["oww"][2])
                else:
                    tmp = self.eq3.windows[key][0] + datetime.timedelta(seconds=self.setup.intervals["wrn"][1])
                if tmp < dt:
                    return 1
                else:
                    # silence is over
                    self.eq3.windows[key][1] = False

        # increment warning counter for this key
        self.eq3.windows[key][2] += 1
        if self.eq3.windows[key][2] > self.setup.abnormalCount:
            logmsg.update(
                "Abnormal #warnings for device [" + str(key) + "], name [" + str(self.eq3.devices[key][2]) + "]")
            self.eq3.windows[key][2] = 0
        return 0
Beispiel #48
0
def load(bridgefile):
    global bridgeclient, cw
    # prepare dictionary
    lcw = {}
    for k in cw.iteritems():
        # key : [default, literal]
        lcw.update({k[1][0]: [k[1][1], k[1][2]]})

    if os.path.exists(bridgefile):
        with open(bridgefile, "r") as f:
            for line in f:
                t = (line.rstrip("\r\n")).split('=')
                localcw = t[0]
                setvalue = t[1]
                if localcw in lcw:
                    process_bridge_cw(localcw, lcw[localcw][0], setvalue)
            f.close()
        logmsg.update("Bridge file loaded.", 'D')
    # >>>>>>> updateAllTimes()
    else:
        for k, v in lcw.iteritems():
            process_bridge_cw(k, v[0], v[0])
        logmsg.update("Error loading bridge file, using defaults!", 'E')
Beispiel #49
0
    def process_windows(self, ow):
        """
        Process dictionary and set ventilation status, then update owl web file
        :param ow: dictionary, open windows
        :return: nothing
        """
        # if count of open windows >= number of windows, that mean ventilation
        if len(ow) >= self.setup.ventilate_num:
            self.var.ventilating = True
        else:
            self.var.ventilating = False

        # write second web file

        secweb.write("owl", ow)
        # write bridge value
        bridge.put("owl", ow)
        # if open window warning is on and open window(s) count < number of open windows, that mean ventilation
        # send warnings for these windows
        if not self.setup.no_oww and len(ow) < self.setup.ventilate_num:
            for k, v in ow.iteritems():
                if self._is_win_open_too_long(k):
                    logmsg.update("Warning condition for window " + str(k) + " met")
                    self.send_warning("window", k, "")
Beispiel #50
0
 def check_var(self):
     """
     Check if variables are set correctly, reports any problem
     :return: nothing
     """
     if self.setup.valve_num > len(self.eq3.valves):
         logmsg.update("You have only " + str(len(self.eq3.valves)) +
                       " valves, but you want to " + str(self.setup.valve_num) +
                       " of them be checked to turn on heating!")
         self.setup.valve_num = len(self.eq3.valves)
     if self.setup.valve_switch > 90:
         logmsg.update("Valve switch position over 90%!")
         self.setup.valve_switch = 90
     if self.setup.svpnmw > 100:
         logmsg.update("Single valve switch position over 100%! Please check svpnmw variable!")
     # uncomment below if you want auto correct value
     # self.setup.svpnmw = 100
     if self.setup.valve_switch > self.setup.svpnmw:
         logmsg.update("svpnmw (" + str(self.setup.svpnmw) +
                       "%) is less or equal to valve switch setup (" + str(self.setup.valve_switch) + "%)!")
         self.setup.svpnmw = self.setup.valve_switch
Beispiel #51
0
 def _literal_process(self, bridge_data, obj_prefix="self."):
     """
     Process bridge string, update variables as typed in bridge.cw dictionary
     :param bridge_data: dictionary
     :param obj_prefix: string
     :return: nothing
     """
     try:
         for k, v in bridge_data.iteritems():
             if k in bridge.pcw:
                 pcw_v = bridge.pcw[k]
                 if pcw_v[1]:
                     d = pcw_v[2].split(".")
                     default = pcw_v[0]
                     cwt = type(default)
                     obj = obj_prefix + d[0]
                     name = d[1]
                     if cwt is str:
                         value = str(v)
                     elif cwt is int:
                         value = int(v)
                     elif cwt is bool:
                         value = bool(v)
                     elif cwt is float:
                         value = float(v)
                     elif cwt is dict:
                         value = ast.literal_eval(v)
                     else:
                         value = v
                     try:
                         obj_obj = eval(obj)
                     except SyntaxError:
                         logmsg.update(
                             "Error evaluating object: " + str(obj), 'E')
                     else:
                         try:
                             setattr(obj_obj, name, value)
                             # logmsg.debug("object:", obj, ", name:", name, " to:", value)
                         except NameError:
                             logmsg.update(
                                 "Error processing object: " + str(obj) +
                                 ", with name: " + str(name), 'E')
     except AttributeError:
         logmsg.update(
             'Bridge file has attribute error. Possibly file missing.')
Beispiel #52
0
def load(bridge_file):
    """
    Load data from bridge_file and return dictionary or None
    :param bridge_file: string
    :return: dictionary
    """
    data = {}
    if os.path.exists(bridge_file):
        with open(bridge_file, "r") as f:
            try:
                data = json.load(f)
            except ValueError:
                logmsg.update("Bridge value error during loading bridge!", 'E')
            finally:
                f.close()
        logmsg.update("Bridge file loaded.", 'D')
    else:
        logmsg.update("Error loading bridge file, file not exist!", 'E')
        # load empty dict, not None
        # data = None
        data = {}
    return data
Beispiel #53
0
def save(bridge_file):
    """
    Save bridge to bridge_file, if success return True, else False
    :param bridge_file: string
    :return: boolean
    """
    global bridge_client
    try:
        tmp = bridge_client.getall()
    except ValueError:
        logmsg.update("Error reading bridge!", 'E')
    else:
        try:
            f = open(bridge_file, "w")
        except IOError:
            logmsg.update("Error writing to bridge file!", 'E')
        else:
            f.write(json.dumps(tmp, sort_keys=True))
            f.close()
            logmsg.update("Bridge file (" + str(bridge_file) + ") saved.", 'D')
            return True
    return False
Beispiel #54
0
def do(version):
    """
    Perform update
    :param version: string
    :return: boolean, True if something updated
    """
    home_dir = "/root/thermeq3"
    chk, filename = check_update(version)
    result = False
    if chk == 2:
        # unzip files
        with zipfile.ZipFile(home_dir + "-install/" + filename, "r") as z:
            try:
                z.extractall(home_dir + "/")
            except Exception:
                logmsg.update("Error during archive extraction", 'E')
            else:
                logmsg.update("Archive successfully extracted.", 'I')
                result = True
    elif chk == 1:
        logmsg.update("Update is not necessary.")
    return result
Beispiel #55
0
 def process_msg(self):
     """
     Process message queue
     :return: nothing
     """
     while len(self.var.msgQ) > 0:
         logmsg.update("Message queue: " + str(self.var.msgQ), 'D')
         wait_cycle = False
         if support.is_yun():
             # this is waiting routine to ensure that msg queue is processed by 32u4 part
             tmp_br = bridge.get("msg")
             if not support.is_empty(tmp_br):
                 time.sleep(self.setup.timeout)
                 wait_cycle = True
         if not wait_cycle:
             to_send = self.var.msgQ.pop()
             logmsg.update("Sending message [" + str(to_send) + "]", 'D')
             # if we are going to reset, save bridge file
             if to_send == "R":
                 bridge.save(self.setup.bridge_file)
             if support.is_yun():
                 # signal to 32u4 that we have something to process
                 bridge.put("msg", to_send)
             elif support.is_rpi():
                 if to_send == "H":
                     # TBI RPI
                     # uncomment line below for RPi
                     # action.do(True)
                     pass
                 elif to_send == "S":
                     # TBI RPI
                     # uncomment line below for RPi
                     # action.do(False)
                     pass
             elif support.is_win():
                 # insert windows code here
                 # print "nt"
                 logmsg.update("Processing message on Windows: " +
                               str(to_send))
Beispiel #56
0
 def _do_thermeq(self):
     """
     Do what thermeq must do
     :return: nothing
     """
     # save open window dictionary for adjustment
     ow = self.get_open_windows()
     eq3_result, eq3_error = self.eq3.read_data(False)
     if eq3_result:
         # set values
         self.get_control_values()
         # log messages
         logmsg.update(
             self._status_msg() + " Checking #" +
             str(self.setup.intervals["max"][0]) + " sec", 'I')
         logmsg.update(self.eq3.plain(), 'I')
         # do control
         self.control()
         # update JSONs
         self.write_strings()
         # set status
         self._set_status()
         # do logging
         self.do_device_logging()
         # do some valve_ignored adjustment
         self.adjust_ignored_valves(ow)
         # save bridge
         self.set_bridge_control_values()
         bridge.save(self.setup.bridge_file)
     else:
         self.var.heating = None
         if any("response" in e for e in eq3_error):
             self.queue_msg('M')
         else:
             self.queue_msg('E')
         # flush error to log
         logmsg.update("".join(str(e) + " " for e in eq3_error), 'E')
Beispiel #57
0
        tmp_dir = os.path.dirname(put_file)
        if not os.path.exists(tmp_dir):
            os.mkdir(tmp_dir)
        try:
            f = file(put_file, "wb")
        except Exception, e:
            err_str = "Problem during saving new version. File: " + put_file + ". Error: " + str(
                e) + " Traceback: " + str(traceback.format_exc())
        else:
            f.write(response)
            f.close()
            err_str = ""
            request.close()
    finally:
        if not err_str == "":
            logmsg.update(err_str)
            return False
    return True


def check_update(version):
    github = "https://github.com/autopower/thermeq3/raw/master/install/current/"
    home_dir = "/root/thermeq3"
    err_str = "Unable to get latest version info - "

    try:
        request = urllib2.urlopen(github + "autoupdate.data")
        response = request.read().rstrip("\r\n")
    except urllib2.HTTPError, e:
        err_str += "HTTPError = " + str(e.reason)
    except urllib2.URLError, e:
Beispiel #58
0
     city = data["query"]["results"]["channel"]["location"][
         "city"]
     temp = int(data["query"]["results"]["channel"]["item"]
                ["condition"]["temp"])
     humidity = int(data["query"]["results"]["channel"]
                    ["atmosphere"]["humidity"])
 except Exception:
     pass
 else:
     # and check if yahoo is correct
     url = "http://api.openweathermap.org/data/2.5/weather?id=" + str(owm_id) + "&appid=" + \
           owm_api_key + "&units=metric"
     try:
         result = json.load(urllib2.urlopen(url))
     except Exception, error:
         logmsg.update("OWM communication error: " + str(error),
                       'E')
         logmsg.update(
             "Traceback: " + str(traceback.format_exc()), 'E')
     else:
         if "main" in result:
             owm_temp = round(result["main"]["temp"])
             yho_temp = round(temp)
             if abs(yho_temp - owm_temp) > 1.5:
                 logmsg.update(
                     "Difference between Yahoo and OWM temperatures. Yahoo="
                     + str(yho_temp) + " OWM=" + str(owm_temp),
                     'I')
                 # end check
         else:
             logmsg.update("Error during parsing result.", 'D')
     logmsg.update(
Beispiel #59
0
    def send_warning(self, selector, dev_key, body_txt):
        dt_now = datetime.datetime.now()

        try:
            device = self.eq3.devices[dev_key]
        except KeyError:
            device = [
                1, "KeyError", "Key Error", 99, 0,
                datetime.datetime(2016, 01, 01, 12, 00, 00), 18, 56, 7
            ]
            device_name = device[2]
            room_name = "Error room"
            logmsg.update("Key error: " + str(dev_key), 'E')
        else:
            device_name = device[2]
            room = device[3]
            room_name = self.eq3.rooms[str(room)]
        sil = self.silence(dev_key, selector == "window")

        if not sil == 1:
            mute_str = "http://" + self.setup.my_ip + ":" + str(self.setup.ext_port) + "/data/put/command/mute:" + \
                       str(dev_key)
            msg = None
            if selector == "window":
                oww = int(
                    (dt_now - self.eq3.windows[dev_key][0]).total_seconds())
                owd = dt_now - self.eq3.devices[dev_key][5]
                if sil == 0 and oww < self.setup.intervals["oww"][1]:
                    return
                msg = mailer.new_compose(selector, room_name[0], device_name,
                                         room_name[0],
                                         str(owd).split('.')[0],
                                         (self.setup.intervals["oww"][0] *
                                          self.eq3.windows[dev_key][3]) / 60,
                                         mute_str,
                                         self.setup.intervals["oww"][2] / 60)
            else:
                if sil == 0 and not self.isrt("wrn"):
                    return
                if selector == "battery" or selector == "error":
                    msg = mailer.new_compose(
                        selector, device_name, device_name, room_name[0],
                        mute_str, self.setup.intervals["wrn"][1] / 60)
                elif selector == "openmax" or selector == "upgrade":
                    msg = mailer.new_compose(selector, "", body_txt)

            if mailer.send_email(self.setup,
                                 msg.as_string()) and selector == "window":
                # original code
                # self.eq3.windows[dev_key][0] = dt_now
                # dev code
                # extend warning period by incrementing multiplicand * oww time
                self.eq3.windows[dev_key][3] += 1
                self.eq3.windows[dev_key][0] = dt_now + datetime.timedelta(
                    seconds=(self.setup.intervals["oww"][0] *
                             self.eq3.windows[dev_key][3]))
                logmsg.update(
                    "Multiplicand for " + str(dev_key) + " updated to " +
                    str(self.eq3.windows[dev_key][3]), 'D')
        else:
            logmsg.update("Warning for device " + str(dev_key) + " is muted!")
Beispiel #60
0
    """
    try:
        server = smtplib.SMTP(eq3_setup.mail_server, eq3_setup.mail_port)
    except Exception, error:
        logmsg.update("Error connecting to mail server " +
                      str(eq3_setup.mail_server) + ":" +
                      str(eq3_setup.mail_port) + ". Error code: " + str(error))
        logmsg.update("Traceback: " + str(traceback.format_exc()))
    else:
        try:
            server.ehlo()
            if server.has_extn('STARTTLS'):
                server.starttls()
                server.ehlo()
            server.login(eq3_setup.from_addr, eq3_setup.from_pwd)
            tmp = str_to_list(eq3_setup.to_addr)
            server.sendmail(eq3_setup.from_addr,
                            str_to_list(eq3_setup.to_addr), message)
        except smtplib.SMTPAuthenticationError:
            logmsg.update("Authentication error during sending email.")
        except smtplib.SMTPRecipientsRefused:
            logmsg.update("Recipient refused.")
        except Exception, error:
            logmsg.update("Error during sending email. Error code: " +
                          str(error))
        else:
            server.quit()
            logmsg.update("Mail was sent.")
            return True
    return False