def run(self): _logger.info("=== HtHttpDaemon.run() {}".format("=" * 100)) global hp try: hp = HtHeatpump(args.device, baudrate=args.baudrate) hp.open_connection() hp.login() rid = hp.get_serial_number() _logger.info( "Connected successfully to heat pump with serial number: {:d}". format(rid)) ver = hp.get_version() _logger.info("Software version: {} ({:d})".format(ver[0], ver[1])) hp.logout() server = HTTPServer((args.ip, args.port), HttpGetHandler) _logger.info("Starting server at: {}".format( server.server_address)) server.serve_forever() # start the server and wait for requests except Exception as ex: _logger.error(ex) sys.exit(2) finally: hp.logout( ) # try to logout for an ordinary cancellation (if possible) hp.close_connection()
def main(): parser = argparse.ArgumentParser( description=textwrap.dedent('''\ Command line tool to create a backup of the Heliotherm heat pump data points. Example: $ python3 %(prog)s --baudrate 9600 --csv backup.csv 'SP,NR=0' [Language]: VAL='0', MIN='0', MAX='4' 'SP,NR=1' [TBF_BIT]: VAL='0', MIN='0', MAX='1' 'SP,NR=2' [Rueckruferlaubnis]: VAL='1', MIN='0', MAX='1' ... '''), formatter_class=argparse.RawDescriptionHelpFormatter, epilog=textwrap.dedent('''\ DISCLAIMER ---------- Please note that any incorrect or careless usage of this program as well as errors in the implementation can damage your heat pump! Therefore, the author does not provide any guarantee or warranty concerning to correctness, functionality or performance and does not accept any liability for damage caused by this program or mentioned information. Thus, use it on your own risk! ''') + "\r\n") parser.add_argument( "-d", "--device", default="/dev/ttyUSB0", type=str, help= "the serial device on which the heat pump is connected, default: %(default)s" ) parser.add_argument( "-b", "--baudrate", default=115200, type=int, # the supported baudrates of the Heliotherm heat pump (HP08S10W-WEB): choices=[9600, 19200, 38400, 57600, 115200], help= "baudrate of the serial connection (same as configured on the heat pump), default: %(default)s" ) parser.add_argument("-j", "--json", type=str, help="write the result to the specified JSON file") parser.add_argument("-c", "--csv", type=str, help="write the result to the specified CSV file") parser.add_argument("-t", "--time", action="store_true", help="measure the execution time") parser.add_argument("-v", "--verbose", action="store_true", help="increase output verbosity by activating logging") parser.add_argument( "--without-values", action="store_true", help= "store heat pump data points without their current value (keep it blank)" ) parser.add_argument( "--max-retries", default=2, type=int, choices=range(0, 11), help= "maximum number of retries for a data point request (0..10), default: %(default)s" ) args = parser.parse_args() # activate logging with level DEBUG in verbose mode if args.verbose: logging.basicConfig(level=logging.DEBUG) else: logging.basicConfig(level=logging.WARNING) hp = HtHeatpump(args.device, baudrate=args.baudrate) start = timer() try: hp.open_connection() hp.login() rid = hp.get_serial_number() print("connected successfully to heat pump with serial number {:d}". format(rid)) ver = hp.get_version() print("software version = {} ({:d})".format(ver[0], ver[1])) result = {} for dp_type in ("SP", "MP"): # for all known data point types result.update({dp_type: {}}) i = 0 # start at zero for each data point type while True: success = False retry = 0 while not success and retry <= args.max_retries: data_point = "{},NR={:d}".format(dp_type, i) # send request for data point to the heat pump hp.send_request(data_point) # ... and wait for the response try: resp = hp.read_response() # search for pattern "NAME=...", "VAL=...", "MAX=..." and "MIN=..." inside the answer m = re.match( r"^{},.*NAME=([^,]+).*VAL=([^,]+).*MAX=([^,]+).*MIN=([^,]+).*$" .format(data_point), resp) if not m: raise IOError( "invalid response for query of data point {!r} [{}]" .format(data_point, resp)) name, value, max, min = m.group( 1, 2, 3, 4) # extract name, value, max and min if args.without_values: value = "" # keep it blank (if desired) print("{!r} [{}]: VAL={!r}, MIN={!r}, MAX={!r}".format( data_point, name, value, min, max)) # store the determined data in the result dict result[dp_type].update({ i: { "name": name, "value": value, "min": min, "max": max } }) success = True except Exception as e: retry += 1 _logger.warning( "try #{:d}/{:d} for query of data point {!r} failed: {!s}" .format(retry, args.max_retries + 1, data_point, e)) # try a reconnect, maybe this will help hp.reconnect() # perform a reconnect try: hp.login(0) # and a new login except Exception: pass # ignore a potential problem if not success: _logger.error( "query of data point {!r} failed after {:d} try/tries". format(data_point, retry)) break else: i += 1 if args.json: # write result to JSON file with open(args.json, 'w') as jsonfile: json.dump(result, jsonfile, indent=4, sort_keys=True) if args.csv: # write result to CSV file with open(args.csv, 'w') as csvfile: fieldnames = ["type", "number", "name", "value", "min", "max"] writer = csv.DictWriter(csvfile, delimiter='\t', fieldnames=fieldnames) writer.writeheader() for dp_type, content in sorted(result.items(), reverse=True): for i, data in content.items(): writer.writerow({ "type": dp_type, "number": i, "name": data["name"], "value": data["value"], "min": data["min"], "max": data["max"] }) except Exception as ex: _logger.error(ex) sys.exit(1) finally: hp.logout() # try to logout for an ordinary cancellation (if possible) hp.close_connection() end = timer() # print execution time only if desired if args.time: print("execution time: {:.2f} sec".format(end - start)) sys.exit(0)
def main(): parser = argparse.ArgumentParser( description=textwrap.dedent('''\ Command line tool to query for the fault list of the heat pump. Example: $ python3 %(prog)s --device /dev/ttyUSB1 #000 [2000-01-01T00:00:00]: 65534, Keine Stoerung #001 [2000-01-01T00:00:00]: 65286, Info: Programmupdate 1 #002 [2000-01-01T00:00:00]: 65285, Info: Initialisiert #003 [2000-01-01T00:00:16]: 00009, HD Schalter #004 [2000-01-01T00:00:20]: 00021, EQ Motorschutz '''), formatter_class=argparse.RawDescriptionHelpFormatter, epilog=textwrap.dedent('''\ DISCLAIMER ---------- Please note that any incorrect or careless usage of this program as well as errors in the implementation can damage your heat pump! Therefore, the author does not provide any guarantee or warranty concerning to correctness, functionality or performance and does not accept any liability for damage caused by this program or mentioned information. Thus, use it on your own risk! ''') + "\r\n") parser.add_argument( "-d", "--device", default="/dev/ttyUSB0", type=str, help= "the serial device on which the heat pump is connected, default: %(default)s" ) parser.add_argument( "-b", "--baudrate", default=115200, type=int, # the supported baudrates of the Heliotherm heat pump (HP08S10W-WEB): choices=[9600, 19200, 38400, 57600, 115200], help= "baudrate of the serial connection (same as configured on the heat pump), default: %(default)s" ) parser.add_argument("-t", "--time", action="store_true", help="measure the execution time") parser.add_argument("-v", "--verbose", action="store_true", help="increase output verbosity by activating logging") parser.add_argument( "-l", "--last", action="store_true", help="print only the last fault message of the heat pump") args = parser.parse_args() # activate logging with level INFO in verbose mode if args.verbose: logging.basicConfig(level=logging.INFO) else: logging.basicConfig(level=logging.ERROR) hp = HtHeatpump(args.device, baudrate=args.baudrate) start = timer() try: hp.open_connection() hp.login() rid = hp.get_serial_number() if args.verbose: _logger.info( "connected successfully to heat pump with serial number {:d}". format(rid)) ver = hp.get_version() if args.verbose: _logger.info("software version = {} ({:d})".format(ver[0], ver[1])) if args.last: # query for the last fault message of the heat pump idx, err, dt, msg = hp.get_last_fault() print("#{:d} [{}]: {:d}, {}".format(idx, dt.isoformat(), err, msg)) else: # query for the whole fault list of the heat pump lst = hp.get_fault_list() for idx, e in lst.items(): print("#{:03d} [{}]: {:05d}, {}".format( idx, e["datetime"].isoformat(), e["error"], e["message"])) except Exception as ex: _logger.error(ex) sys.exit(1) finally: hp.logout() # try to logout for an ordinary cancellation (if possible) hp.close_connection() end = timer() # print execution time only if desired if args.time: print("execution time: {:.2f} sec".format(end - start)) sys.exit(0)
def main(): parser = argparse.ArgumentParser( description=textwrap.dedent('''\ Command shell tool to send raw commands to the Heliotherm heat pump. For commands which deliver more than one response from the heat pump the expected number of responses can be defined by the argument "-r" or "--responses". Example: $ python3 %(prog)s --device /dev/ttyUSB1 "AR,28,29,30" -r 3 > 'AR,28,29,30' < 'AA,28,19,14.09.14-02:08:56,EQ_Spreizung' < 'AA,29,20,14.09.14-11:52:08,EQ_Spreizung' < 'AA,30,65534,15.09.14-09:17:12,Keine Stoerung' '''), formatter_class=argparse.RawDescriptionHelpFormatter, epilog=textwrap.dedent('''\ DISCLAIMER ---------- Please note that any incorrect or careless usage of this program as well as errors in the implementation can damage your heat pump! Therefore, the author does not provide any guarantee or warranty concerning to correctness, functionality or performance and does not accept any liability for damage caused by this program or mentioned information. Thus, use it on your own risk! ''') + "\r\n") parser.add_argument( "-d", "--device", default="/dev/ttyUSB0", type=str, help= "the serial device on which the heat pump is connected, default: %(default)s" ) parser.add_argument( "-b", "--baudrate", default=115200, type=int, # the supported baudrates of the Heliotherm heat pump (HP08S10W-WEB): choices=[9600, 19200, 38400, 57600, 115200], help= "baudrate of the serial connection (same as configured on the heat pump), default: %(default)s" ) parser.add_argument( "-r", "--responses", default=1, type=int, help= "number of expected responses for each given command, default: %(default)s" ) parser.add_argument("-t", "--time", action="store_true", help="measure the execution time") parser.add_argument("-v", "--verbose", action="store_true", help="increase output verbosity by activating logging") parser.add_argument( "cmd", type=str, nargs='+', help= "command(s) to send to the heat pump (without the preceding '~' and the trailing ';')" ) args = parser.parse_args() # activate logging with level DEBUG in verbose mode log_format = "%(asctime)s %(levelname)s [%(name)s|%(funcName)s]: %(message)s" if args.verbose: logging.basicConfig(level=logging.DEBUG, format=log_format) else: logging.basicConfig(level=logging.WARNING, format=log_format) hp = HtHeatpump(args.device, baudrate=args.baudrate) try: hp.open_connection() hp.login() rid = hp.get_serial_number() if args.verbose: _logger.info( "connected successfully to heat pump with serial number {:d}". format(rid)) ver = hp.get_version() if args.verbose: _logger.info("software version = {} ({:d})".format(ver[0], ver[1])) with Timer() as timer: for cmd in args.cmd: # write the given command to the heat pump print("> {!r}".format(cmd)) hp.send_request(cmd) # and read all expected responses for this command for _ in range(args.responses): resp = hp.read_response() print("< {!r}".format(resp)) exec_time = timer.elapsed # print execution time only if desired if args.time: print("execution time: {:.2f} sec".format(exec_time)) except Exception as ex: _logger.exception(ex) sys.exit(1) finally: hp.logout() # try to logout for an ordinary cancellation (if possible) hp.close_connection() sys.exit(0)
def main(): parser = argparse.ArgumentParser( description=textwrap.dedent('''\ Command line tool to query for parameters of the Heliotherm heat pump. Example: $ python3 %(prog)s --device /dev/ttyUSB1 "Temp. Aussen" "Stoerung" Stoerung : False Temp. Aussen: 5.0 '''), formatter_class=argparse.RawDescriptionHelpFormatter, epilog=textwrap.dedent('''\ DISCLAIMER ---------- Please note that any incorrect or careless usage of this program as well as errors in the implementation can damage your heat pump! Therefore, the author does not provide any guarantee or warranty concerning to correctness, functionality or performance and does not accept any liability for damage caused by this program or mentioned information. Thus, use it on your own risk! ''') + "\r\n") parser.add_argument( "-d", "--device", default="/dev/ttyUSB0", type=str, help= "the serial device on which the heat pump is connected, default: %(default)s" ) parser.add_argument( "-b", "--baudrate", default=115200, type=int, # the supported baudrates of the Heliotherm heat pump (HP08S10W-WEB): choices=[9600, 19200, 38400, 57600, 115200], help= "baudrate of the serial connection (same as configured on the heat pump), default: %(default)s" ) parser.add_argument("-j", "--json", action="store_true", help="output will be in JSON format") parser.add_argument("--boolasint", action="store_true", help="boolean values will be stored as '0' and '1'") parser.add_argument("-t", "--time", action="store_true", help="measure the execution time") parser.add_argument("-v", "--verbose", action="store_true", help="increase output verbosity by activating logging") parser.add_argument( "name", type=str, nargs='*', help= "parameter name(s) to query for (as defined in htparams.csv) or omit to query for all known parameters" ) args = parser.parse_args() # activate logging with level DEBUG in verbose mode log_format = "%(asctime)s %(levelname)s [%(name)s|%(funcName)s]: %(message)s" if args.verbose: logging.basicConfig(level=logging.DEBUG, format=log_format) else: logging.basicConfig(level=logging.WARNING, format=log_format) hp = HtHeatpump(args.device, baudrate=args.baudrate) try: hp.open_connection() hp.login() rid = hp.get_serial_number() if args.verbose: _logger.info( "connected successfully to heat pump with serial number {:d}". format(rid)) ver = hp.get_version() if args.verbose: _logger.info("software version = {} ({:d})".format(ver[0], ver[1])) # query for the given parameter(s) with Timer() as timer: values = hp.query(*args.name) exec_time = timer.elapsed for name, val in values.items(): if args.boolasint and HtParams[name].data_type == HtDataTypes.BOOL: values[name] = 1 if val else 0 # print the current value(s) of the retrieved parameter(s) if args.json: print(json.dumps(values, indent=4, sort_keys=True)) else: if len(values) > 1: for name in sorted(values.keys()): print("{:{width}}: {}".format(name, values[name], width=len( max(values.keys(), key=len)))) elif len(values) == 1: print(next(iter(values.values()))) # print execution time only if desired if args.time: print("execution time: {:.2f} sec".format(exec_time)) except Exception as ex: _logger.exception(ex) sys.exit(1) finally: hp.logout() # try to logout for an ordinary cancellation (if possible) hp.close_connection() sys.exit(0)
def main(): parser = argparse.ArgumentParser( description = textwrap.dedent('''\ Command line tool to get and set date and time on the Heliotherm heat pump. To change date and/or time on the heat pump the date and time has to be passed in ISO 8601 format (YYYY-MM-DDTHH:MM:SS) to the program. It is also possible to pass an empty string, therefore the current date and time of the host will be used. If nothing is passed to the program the current date and time on the heat pump will be returned. Example: $ python3 %(prog)s --device /dev/ttyUSB1 --baudrate 9600 Tuesday, 2017-11-21T21:48:04 $ python3 %(prog)s -d /dev/ttyUSB1 -b 9600 "2008-09-03T20:56:35" Wednesday, 2008-09-03T20:56:35 '''), formatter_class = argparse.RawDescriptionHelpFormatter, epilog = textwrap.dedent('''\ DISCLAIMER ---------- Please note that any incorrect or careless usage of this program as well as errors in the implementation can damage your heat pump! Therefore, the author does not provide any guarantee or warranty concerning to correctness, functionality or performance and does not accept any liability for damage caused by this program or mentioned information. Thus, use it on your own risk! ''') + "\r\n") parser.add_argument( "-d", "--device", default = "/dev/ttyUSB0", type = str, help = "the serial device on which the heat pump is connected, default: %(default)s") parser.add_argument( "-b", "--baudrate", default = 115200, type = int, # the supported baudrates of the Heliotherm heat pump (HP08S10W-WEB): choices = [9600, 19200, 38400, 57600, 115200], help = "baudrate of the serial connection (same as configured on the heat pump), default: %(default)s") parser.add_argument( "-t", "--time", action = "store_true", help = "measure the execution time") parser.add_argument( "-v", "--verbose", action = "store_true", help = "increase output verbosity by activating logging") parser.add_argument( "datetime", type = str, nargs = '?', help = "date and time in ISO 8601 format (YYYY-MM-DDTHH:MM:SS), if empty current date and time will be used, " "if not specified current date and time on the heat pump will be returned") args = parser.parse_args() # activate logging with level INFO in verbose mode if args.verbose: logging.basicConfig(level=logging.INFO) else: logging.basicConfig(level=logging.ERROR) hp = HtHeatpump(args.device, baudrate=args.baudrate) start = timer() try: hp.open_connection() hp.login() rid = hp.get_serial_number() if args.verbose: _logger.info("connected successfully to heat pump with serial number {:d}".format(rid)) ver = hp.get_version() if args.verbose: _logger.info("software version = {} ({:d})".format(ver[0], ver[1])) if args.datetime is None: # get current date and time on the heat pump dt, wd = hp.get_date_time() print("{}, {}".format(WEEKDAYS[wd - 1], dt.isoformat())) else: # set current date and time on the heat pump if not args.datetime: # no date and time given, so use the current date and time on the host dt = datetime.datetime.now() else: # otherwise translate the given string to a valid datetime object dt = datetime.datetime.strptime(args.datetime, "%Y-%m-%dT%H:%M:%S") dt, wd = hp.set_date_time(dt) print("{}, {}".format(WEEKDAYS[wd - 1], dt.isoformat())) except Exception as ex: _logger.error(ex) sys.exit(1) finally: hp.logout() # try to logout for an ordinary cancellation (if possible) hp.close_connection() end = timer() # print execution time only if desired if args.time: print("execution time: {:.2f} sec".format(end - start)) sys.exit(0)
def main(): parser = argparse.ArgumentParser( description=textwrap.dedent('''\ Command line tool to set the value of a specific parameter of the heat pump. Example: $ python3 %(prog)s --device /dev/ttyUSB1 "HKR Soll_Raum" "21.5" 21.5 '''), formatter_class=argparse.RawDescriptionHelpFormatter, epilog=textwrap.dedent('''\ DISCLAIMER ---------- Please note that any incorrect or careless usage of this program as well as errors in the implementation can damage your heat pump! Therefore, the author does not provide any guarantee or warranty concerning to correctness, functionality or performance and does not accept any liability for damage caused by this program or mentioned information. Thus, use it on your own risk! ''') + "\r\n") parser.add_argument( "-d", "--device", default="/dev/ttyUSB0", type=str, help= "the serial device on which the heat pump is connected, default: %(default)s" ) parser.add_argument( "-b", "--baudrate", default=115200, type=int, # the supported baudrates of the Heliotherm heat pump (HP08S10W-WEB): choices=[9600, 19200, 38400, 57600, 115200], help= "baudrate of the serial connection (same as configured on the heat pump), default: %(default)s" ) parser.add_argument("-t", "--time", action="store_true", help="measure the execution time") parser.add_argument("-v", "--verbose", action="store_true", help="increase output verbosity by activating logging") parser.add_argument("name", type=str, nargs=1, action=ParamNameAction, help="parameter name (as defined in htparams.csv)") parser.add_argument("value", type=str, nargs=1, help="parameter value (as string)") args = parser.parse_args() # activate logging with level INFO in verbose mode if args.verbose: logging.basicConfig(level=logging.INFO) else: logging.basicConfig(level=logging.ERROR) hp = HtHeatpump(args.device, baudrate=args.baudrate) start = timer() try: hp.open_connection() hp.login() rid = hp.get_serial_number() if args.verbose: _logger.info( "connected successfully to heat pump with serial number {:d}". format(rid)) ver = hp.get_version() if args.verbose: _logger.info("software version = {} ({:d})".format(ver[0], ver[1])) # convert the passed value (as string) to the specific data type value = HtParams[args.name[0]].from_str(args.value[0]) # set the parameter of the heat pump to the passed value value = hp.set_param(args.name[0], value) print(value) except Exception as ex: _logger.error(ex) sys.exit(1) finally: hp.logout() # try to logout for an ordinary cancellation (if possible) hp.close_connection() end = timer() # print execution time only if desired if args.time: print("execution time: {:.2f} sec".format(end - start)) sys.exit(0)
def test_get_serial_number(self, hthp: HtHeatpump): rid = hthp.get_serial_number() assert isinstance(rid, int), "'rid' must be of type int" assert rid > 0
def main(): logging.basicConfig( level=logging.INFO, format="%(asctime)s %(levelname)s [%(name)s|%(funcName)s]: %(message)s" ) hp = HtHeatpump("/dev/ttyUSB0", baudrate=115200) hp.open_connection() hp.login() rid = hp.get_serial_number() print("connected successfully to heat pump with serial number {:d}".format( rid)) ver = hp.get_version() print("software version = {} ({:d})".format(ver[0], ver[1])) names = HtParams.of_type("MP").keys() t_query = t_fast_query = 0.0 for i in range(10): start = timer() values = hp.query(*names) t_query += (timer() - start) start = timer() values = hp.fast_query(*names) t_fast_query += (timer() - start) i += 1 t_query = t_query / i t_fast_query = t_fast_query / i print("\n" + "-" * 100) print("HtHeatpump.query({:d}) execution time: {:.3f} sec".format( len(names), t_query)) print("HtHeatpump.fast_query({:d}) execution time: {:.3f} sec".format( len(names), t_fast_query)) print("-> {:.3f} x faster".format(t_query / t_fast_query)) while True: print("\n" + "-" * 100) rand_names = random.sample(names, random.randint(0, len(names))) print("{!s}".format(rand_names)) # fast query for the given parameter(s) values = hp.fast_query(*rand_names) # print the current value(s) of the retrieved parameter(s) print(", ".join( map(lambda name: "{!r} = {}".format(name, values[name]), values))) #for name in sorted(values.keys()): # print("{:{width}} [{},{:02d}]: {}".format(name, # HtParams[name].dp_type, # HtParams[name].dp_number, # values[name], # width=len(max(values.keys(), key=len)))) for i in range(5, 0, -1): #print(i) sys.stdout.write("\rContinue in {:d}s ...".format(i)) sys.stdout.flush() time.sleep(1) print("\rContinue in 0s ...") hp.logout() # try to logout for an ordinary cancellation (if possible) hp.close_connection() sys.exit(0)
def main(): parser = argparse.ArgumentParser( description=textwrap.dedent('''\ Command line tool to query for the time programs of the heat pump. Example: $ python3 %(prog)s --device /dev/ttyUSB1 --baudrate 9600 idx=0, name='Warmwasser', ead=7, nos=2, ste=15, nod=7, entries=[] idx=1, name='Zirkulationspumpe', ead=7, nos=2, ste=15, nod=7, entries=[] idx=2, name='Heizung', ead=7, nos=3, ste=15, nod=7, entries=[] idx=3, name='Mischer 1', ead=7, nos=3, ste=15, nod=7, entries=[] idx=4, name='Mischer 2', ead=7, nos=3, ste=15, nod=7, entries=[] '''), formatter_class=argparse.RawDescriptionHelpFormatter, epilog=textwrap.dedent('''\ DISCLAIMER ---------- Please note that any incorrect or careless usage of this program as well as errors in the implementation can damage your heat pump! Therefore, the author does not provide any guarantee or warranty concerning to correctness, functionality or performance and does not accept any liability for damage caused by this program or mentioned information. Thus, use it on your own risk! ''') + "\r\n") parser.add_argument( "-d", "--device", default="/dev/ttyUSB0", type=str, help= "the serial device on which the heat pump is connected, default: %(default)s" ) parser.add_argument( "-b", "--baudrate", default=115200, type=int, # the supported baudrates of the Heliotherm heat pump (HP08S10W-WEB): choices=[9600, 19200, 38400, 57600, 115200], help= "baudrate of the serial connection (same as configured on the heat pump), default: %(default)s" ) parser.add_argument("-t", "--time", action="store_true", help="measure the execution time") parser.add_argument("-v", "--verbose", action="store_true", help="increase output verbosity by activating logging") parser.add_argument( "-j", "--json", type=str, help="write the time program entries to the specified JSON file") parser.add_argument( "-c", "--csv", type=str, help="write the time program entries to the specified CSV file") parser.add_argument( "index", type=int, nargs='?', help= "time program index to query for (omit to get the list of available time programs of the heat pump)" ) parser.add_argument( "day", type=int, nargs='?', help="number of day of a specific time program to query for") parser.add_argument( "entry", type=int, nargs='?', help="number of entry of a specific day of a time program to query for" ) args = parser.parse_args() # activate logging with level DEBUG in verbose mode log_format = "%(asctime)s %(levelname)s [%(name)s|%(funcName)s]: %(message)s" if args.verbose: logging.basicConfig(level=logging.DEBUG, format=log_format) else: logging.basicConfig(level=logging.WARNING, format=log_format) hp = HtHeatpump(args.device, baudrate=args.baudrate) try: hp.open_connection() hp.login() rid = hp.get_serial_number() if args.verbose: _logger.info( "connected successfully to heat pump with serial number {:d}". format(rid)) ver = hp.get_version() if args.verbose: _logger.info("software version = {} ({:d})".format(ver[0], ver[1])) if args.index is not None and args.day is not None and args.entry is not None: # query for a specific time program entry of the heat pump with Timer() as timer: time_prog_entry = hp.get_time_prog_entry( args.index, args.day, args.entry) exec_time = timer.elapsed print("[idx={:d}, day={:d}, entry={:d}]: {!s}".format( args.index, args.day, args.entry, time_prog_entry)) # write time program entry to JSON file if args.json: with open(args.json, 'w') as jsonfile: json.dump(time_prog_entry.as_json(), jsonfile, indent=4, sort_keys=True) # write time program entry to CSV file if args.csv: with open(args.csv, 'w') as csvfile: csvfile.write("# idx={:d}, day={:d}, entry={:d}".format( args.index, args.day, args.entry)) fieldnames = ["state", "start", "end"] writer = csv.DictWriter(csvfile, delimiter=',', fieldnames=fieldnames) writer.writeheader() writer.writerow(time_prog_entry.as_json()) elif args.index is not None and args.day is not None: # query for the entries of a specific day of a time program of the heat pump with Timer() as timer: time_prog = hp.get_time_prog(args.index, with_entries=True) exec_time = timer.elapsed print("[idx={:d}]: {!s}".format(args.index, time_prog)) day_entries = time_prog.entries_of_day(args.day) for num in range(len(day_entries)): print("[day={:d}, entry={:d}]: {!s}".format( args.day, num, day_entries[num])) # write time program entries of the specified day to JSON file if args.json: with open(args.json, 'w') as jsonfile: json.dump([entry.as_json() for entry in day_entries], jsonfile, indent=4, sort_keys=True) # write time program entries of the specified day to CSV file if args.csv: with open(args.csv, 'w') as csvfile: csvfile.write("# {!s}\n".format(time_prog)) fieldnames = ["day", "entry", "state", "start", "end"] writer = csv.DictWriter(csvfile, delimiter=',', fieldnames=fieldnames) writer.writeheader() for num in range(len(day_entries)): row = {"day": args.day, "entry": num} row.update(day_entries[num].as_json()) writer.writerow(row) elif args.index is not None: # query for the entries of a specific time program of the heat pump with Timer() as timer: time_prog = hp.get_time_prog(args.index, with_entries=True) exec_time = timer.elapsed print("[idx={:d}]: {!s}".format(args.index, time_prog)) for (day, num) in [(day, num) for day in range(time_prog.number_of_days) for num in range(time_prog.entries_a_day)]: entry = time_prog.entry(day, num) print("[day={:d}, entry={:d}]: {!s}".format(day, num, entry)) # write time program entries to JSON file if args.json: with open(args.json, 'w') as jsonfile: json.dump(time_prog.as_json(), jsonfile, indent=4, sort_keys=True) # write time program entries to CSV file if args.csv: with open(args.csv, 'w') as csvfile: csvfile.write("# {!s}\n".format(time_prog)) fieldnames = ["day", "entry", "state", "start", "end"] writer = csv.DictWriter(csvfile, delimiter=',', fieldnames=fieldnames) writer.writeheader() for (day, num) in [ (day, num) for day in range(time_prog.number_of_days) for num in range(time_prog.entries_a_day) ]: row = {"day": day, "entry": num} row.update(time_prog.entry(day, num).as_json()) writer.writerow(row) else: # query for all available time programs of the heat pump with Timer() as timer: time_progs = hp.get_time_progs() exec_time = timer.elapsed for time_prog in time_progs: print("{!s}".format(time_prog)) keys = ["index", "name", "ead", "nos", "ste", "nod"] data = [] for time_prog in time_progs: data.append(time_prog.as_json(with_entries=False)) # write time programs to JSON file if args.json: with open(args.json, 'w') as jsonfile: json.dump(data, jsonfile, indent=4, sort_keys=True) # write time programs to CSV file if args.csv: with open(args.csv, 'w') as csvfile: writer = csv.DictWriter(csvfile, delimiter=',', fieldnames=keys) writer.writeheader() writer.writerows(data) # print execution time only if desired if args.time: print("execution time: {:.2f} sec".format(exec_time)) except Exception as ex: _logger.exception(ex) sys.exit(1) finally: hp.logout() # try to logout for an ordinary cancellation (if possible) hp.close_connection() sys.exit(0)
def main(): parser = argparse.ArgumentParser( description=textwrap.dedent('''\ Command line tool to query for the fault list of the heat pump. Example: $ python3 %(prog)s --device /dev/ttyUSB1 #000 [2000-01-01T00:00:00]: 65534, Keine Stoerung #001 [2000-01-01T00:00:00]: 65286, Info: Programmupdate 1 #002 [2000-01-01T00:00:00]: 65285, Info: Initialisiert #003 [2000-01-01T00:00:16]: 00009, HD Schalter #004 [2000-01-01T00:00:20]: 00021, EQ Motorschutz '''), formatter_class=argparse.RawDescriptionHelpFormatter, epilog=textwrap.dedent('''\ DISCLAIMER ---------- Please note that any incorrect or careless usage of this program as well as errors in the implementation can damage your heat pump! Therefore, the author does not provide any guarantee or warranty concerning to correctness, functionality or performance and does not accept any liability for damage caused by this program or mentioned information. Thus, use it on your own risk! ''') + "\r\n") parser.add_argument( "-d", "--device", default="/dev/ttyUSB0", type=str, help= "the serial device on which the heat pump is connected, default: %(default)s" ) parser.add_argument( "-b", "--baudrate", default=115200, type=int, # the supported baudrates of the Heliotherm heat pump (HP08S10W-WEB): choices=[9600, 19200, 38400, 57600, 115200], help= "baudrate of the serial connection (same as configured on the heat pump), default: %(default)s" ) parser.add_argument("-t", "--time", action="store_true", help="measure the execution time") parser.add_argument("-v", "--verbose", action="store_true", help="increase output verbosity by activating logging") parser.add_argument( "-l", "--last", action="store_true", help="print only the last fault message of the heat pump") parser.add_argument("-j", "--json", type=str, help="write the fault list to the specified JSON file") parser.add_argument("-c", "--csv", type=str, help="write the fault list to the specified CSV file") parser.add_argument("index", type=int, nargs='*', help="fault list index/indices to query for") args = parser.parse_args() # activate logging with level DEBUG in verbose mode log_format = "%(asctime)s %(levelname)s [%(name)s|%(funcName)s]: %(message)s" if args.verbose: logging.basicConfig(level=logging.DEBUG, format=log_format) else: logging.basicConfig(level=logging.WARNING, format=log_format) hp = HtHeatpump(args.device, baudrate=args.baudrate) try: hp.open_connection() hp.login() rid = hp.get_serial_number() if args.verbose: _logger.info( "connected successfully to heat pump with serial number {:d}". format(rid)) ver = hp.get_version() if args.verbose: _logger.info("software version = {} ({:d})".format(ver[0], ver[1])) if args.last: # query for the last fault message of the heat pump with Timer() as timer: idx, err, dt, msg = hp.get_last_fault() exec_time = timer.elapsed fault_list = [{ "index": idx, # fault list index "error": err, # error code "datetime": dt.isoformat(), # date and time of the entry "message": msg, # error message }] print("#{:03d} [{}]: {:05d}, {}".format(idx, dt.isoformat(), err, msg)) else: # query for the given fault list entries of the heat pump with Timer() as timer: fault_list = hp.get_fault_list(*args.index) exec_time = timer.elapsed for entry in fault_list: entry["datetime"] = entry["datetime"].isoformat( ) # convert "datetime" dict entry to str print("#{:03d} [{}]: {:05d}, {}".format( entry["index"], entry["datetime"], entry["error"], entry["message"])) if args.json: # write fault list entries to JSON file with open(args.json, 'w') as jsonfile: json.dump(fault_list, jsonfile, indent=4, sort_keys=True) if args.csv: # write fault list entries to CSV file with open(args.csv, 'w') as csvfile: fieldnames = ["index", "datetime", "error", "message"] writer = csv.DictWriter(csvfile, delimiter=',', fieldnames=fieldnames) writer.writeheader() for entry in fault_list: writer.writerow({n: entry[n] for n in fieldnames}) # print execution time only if desired if args.time: print("execution time: {:.2f} sec".format(exec_time)) except Exception as ex: _logger.exception(ex) sys.exit(1) finally: hp.logout() # try to logout for an ordinary cancellation (if possible) hp.close_connection() sys.exit(0)
def main(): parser = argparse.ArgumentParser( description=textwrap.dedent('''\ Command line tool to create a backup of the Heliotherm heat pump settings. Example: $ python3 %(prog)s --baudrate 9600 --csv backup.csv 'SP,NR=0' [Language]: 0 'SP,NR=1' [TBF_BIT]: 0 'SP,NR=2' [Rueckruferlaubnis]: 1 ... '''), formatter_class=argparse.RawDescriptionHelpFormatter, epilog=textwrap.dedent('''\ DISCLAIMER ---------- Please note that any incorrect or careless usage of this program as well as errors in the implementation can damage your heat pump! Therefore, the author does not provide any guarantee or warranty concerning to correctness, functionality or performance and does not accept any liability for damage caused by this program or mentioned information. Thus, use it on your own risk! ''') + "\r\n") parser.add_argument( "-d", "--device", default="/dev/ttyUSB0", type=str, help= "the serial device on which the heat pump is connected, default: %(default)s" ) parser.add_argument( "-b", "--baudrate", default=115200, type=int, # the supported baudrates of the Heliotherm heat pump (HP08S10W-WEB): choices=[9600, 19200, 38400, 57600, 115200], help= "baudrate of the serial connection (same as configured on the heat pump), default: %(default)s" ) parser.add_argument("-j", "--json", type=str, help="write the result to the specified JSON file") parser.add_argument("-c", "--csv", type=str, help="write the result to the specified CSV file") parser.add_argument("-t", "--time", action="store_true", help="measure the execution time") parser.add_argument("-v", "--verbose", action="store_true", help="increase output verbosity by activating logging") args = parser.parse_args() # activate logging with level INFO in verbose mode if args.verbose: logging.basicConfig(level=logging.INFO) else: logging.basicConfig(level=logging.ERROR) hp = HtHeatpump(args.device, baudrate=args.baudrate) start = timer() try: hp.open_connection() hp.login() rid = hp.get_serial_number() if args.verbose: _logger.info( "connected successfully to heat pump with serial number {:d}". format(rid)) ver = hp.get_version() if args.verbose: _logger.info("software version = {} ({:d})".format(ver[0], ver[1])) result = {} for dp_type in ("SP", "MP"): # for all known data point types result.update({dp_type: {}}) i = -1 while True: i += 1 data_point = "{},NR={:d}".format(dp_type, i) # send request for data point to the heat pump hp.send_request(data_point) # ... and wait for the response try: resp = hp.read_response() # search for pattern "NAME=..." and "VAL=..." inside the answer m = re.match( "^{},.*NAME=([^,]+).*VAL=([^,]+).*$".format( data_point), resp) if not m: raise IOError( "invalid response for query of data point {!r} [{}]" .format(data_point, resp)) name, value = m.group(1, 2) # extract name and value print("{!r} [{}]: {}".format(data_point, name, value)) # store the determined data in the result dict result[dp_type].update({i: {"name": name, "value": value}}) except Exception as e: _logger.warning( "query of data point {!r} failed: {!s}".format( data_point, e)) # hp.reconnect() # perform a reconnect break if args.json: # write result to JSON file with open(args.json, 'w') as jsonfile: json.dump(result, jsonfile, indent=4, sort_keys=True) if args.csv: # write result to CSV file with open(args.csv, 'w') as csvfile: fieldnames = ["type", "number", "name", "value"] writer = csv.DictWriter(csvfile, fieldnames=fieldnames) writer.writeheader() for dp_type, content in result.items(): for i, data in content.items(): writer.writerow({ "type": dp_type, "number": i, "name": data["name"], "value": data["value"] }) except Exception as ex: _logger.error(ex) sys.exit(1) finally: hp.logout() # try to logout for an ordinary cancellation (if possible) hp.close_connection() end = timer() # print execution time only if desired if args.time: print("execution time: {:.2f} sec".format(end - start)) sys.exit(0)