def test_fast_query(self, hthp: HtHeatpump): values = hthp.fast_query() assert isinstance(values, dict), "'values' must be of type dict" assert len(values) == len(HtParams.of_type("MP")) for n, v in values.items(): assert n in HtParams assert v is not None assert HtParams[n].in_limits(v)
class TestHtHeatpump: @pytest.mark.run_if_connected def test_open_connection(self, hthp: HtHeatpump): assert hthp.is_open with pytest.raises(IOError): hthp.open_connection() #assert 0 @pytest.mark.parametrize("action", [ VerifyAction.NONE(), {VerifyAction.NAME}, {VerifyAction.NAME, VerifyAction.MIN}, {VerifyAction.NAME, VerifyAction.MIN, VerifyAction.MAX}, { VerifyAction.NAME, VerifyAction.MIN, VerifyAction.MAX, VerifyAction.VALUE }, {VerifyAction.MIN, VerifyAction.MAX, VerifyAction.VALUE}, {VerifyAction.MAX, VerifyAction.VALUE}, {VerifyAction.VALUE}, VerifyAction.ALL() ]) def test_verify_param_action(self, cmdopt_device: str, cmdopt_baudrate: int, action: set): hp = HtHeatpump(device=cmdopt_device, baudrate=cmdopt_baudrate) val = hp.verify_param_action assert isinstance(val, set) hp.verify_param_action = action assert hp.verify_param_action == action hp.verify_param_action = val #assert 0 def test_verify_param_error(self, cmdopt_device: str, cmdopt_baudrate: int): hp = HtHeatpump(device=cmdopt_device, baudrate=cmdopt_baudrate) val = hp.verify_param_error assert isinstance(val, bool) hp.verify_param_error = True assert hp.verify_param_error is True hp.verify_param_error = False assert hp.verify_param_error is False hp.verify_param_error = val #assert 0 def test_send_request(self, cmdopt_device: str, cmdopt_baudrate: int): hp = HtHeatpump(device=cmdopt_device, baudrate=cmdopt_baudrate) with pytest.raises(IOError): hp.send_request(r"LIN") #assert 0 def test_read_response(self, cmdopt_device: str, cmdopt_baudrate: int): hp = HtHeatpump(device=cmdopt_device, baudrate=cmdopt_baudrate) with pytest.raises(IOError): hp.read_response() #assert 0 @pytest.mark.run_if_connected @pytest.mark.usefixtures("reconnect") 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 #assert 0 @pytest.mark.run_if_connected @pytest.mark.usefixtures("reconnect") def test_get_version(self, hthp: HtHeatpump): version = hthp.get_version() # ( "3.0.20", 2321 ) assert isinstance(version, tuple), "'version' must be of type tuple" assert len(version) == 2 ver_str, ver_num = version assert isinstance(ver_str, str), "'ver_str' must be of type str" m = re.match(r"^(\d+).(\d+).(\d+)$", ver_str) assert m is not None, "invalid version string [{!r}]".format(ver_str) assert isinstance(ver_num, int), "'ver_num' must be of type int" assert ver_num > 0 hthp.send_request(r"SP,NR=9") resp = hthp.read_response() m = re.match(r"^SP,NR=9,.*NAME=([^,]+).*VAL=([^,]+).*$", resp) assert m is not None, "invalid response for query of the software version [{!r}]".format( resp) assert ver_str == m.group(1).strip() assert ver_num == int(m.group(2)) #assert 0 @pytest.mark.run_if_connected @pytest.mark.usefixtures("reconnect") def test_get_date_time(self, hthp: HtHeatpump): date_time = hthp.get_date_time() # (datetime.datetime(...), 2) # 2 = Tuesday assert isinstance(date_time, tuple), "'date_time' must be of type tuple" assert len(date_time) == 2 dt, weekday = date_time assert isinstance(dt, datetime.datetime), "'dt' must be of type datetime" assert isinstance(weekday, int), "'weekday' must be of type int" assert weekday in range(1, 8) #assert 0 @pytest.mark.run_if_connected @pytest.mark.usefixtures("reconnect") def test_set_date_time(self, hthp: HtHeatpump): pass # TODO #assert 0 def test_set_date_time_raises_TypeError(self, cmdopt_device: str, cmdopt_baudrate: int): hp = HtHeatpump(device=cmdopt_device, baudrate=cmdopt_baudrate) with pytest.raises(TypeError): hp.set_date_time(123) # type: ignore #assert 0 @pytest.mark.run_if_connected @pytest.mark.usefixtures("reconnect") def test_get_last_fault(self, hthp: HtHeatpump): fault = hthp.get_last_fault() # (29, 20, datetime.datetime(...), "EQ_Spreizung") assert isinstance(fault, tuple), "'fault' must be of type tuple" assert len(fault) == 4 index, error, dt, msg = fault assert isinstance(index, int), "'index' must be of type int" assert 0 <= index < hthp.get_fault_list_size() assert isinstance(error, int), "'error' must be of type int" assert error >= 0 assert isinstance(dt, datetime.datetime), "'dt' must be of type datetime" assert isinstance(msg, str), "'msg' must be of type str" #assert 0 @pytest.mark.run_if_connected @pytest.mark.usefixtures("reconnect") def test_get_fault_list_size(self, hthp: HtHeatpump): size = hthp.get_fault_list_size() assert isinstance(size, int), "'size' must be of type int" assert size >= 0 #assert 0 @pytest.mark.run_if_connected @pytest.mark.usefixtures("reconnect") def test_get_fault_list(self, hthp: HtHeatpump): fault_list = hthp.get_fault_list() # [ { "index": 29, # fault list index # "error": 20, # error code # "datetime": datetime.datetime(...), # date and time of the entry # "message": "EQ_Spreizung", # error message # }, # # ... # ] assert isinstance(fault_list, list), "'fault_list' must be of type list" for entry in fault_list: assert isinstance(entry, dict), "'entry' must be of type dict" index = entry["index"] assert isinstance(index, int), "'index' must be of type int" assert 0 <= index < hthp.get_fault_list_size() error = entry["error"] assert isinstance(error, int), "'error' must be of type int" assert error >= 0 dt = entry["datetime"] assert isinstance( dt, datetime.datetime), "'dt' must be of type datetime" msg = entry["message"] assert isinstance(msg, str), "'msg' must be of type str" #assert 0 @pytest.mark.run_if_connected @pytest.mark.usefixtures("reconnect") def test_get_fault_list_with_index(self, hthp: HtHeatpump): size = hthp.get_fault_list_size() assert isinstance(size, int), "'size' must be of type int" assert size >= 0 for i in range(size): fault_list = hthp.get_fault_list(i) assert isinstance(fault_list, list), "'fault_list' must be of type list" assert len(fault_list) == 1 entry = fault_list[0] assert isinstance(entry, dict), "'entry' must be of type dict" index = entry["index"] assert isinstance(index, int), "'index' must be of type int" assert 0 <= index < hthp.get_fault_list_size() error = entry["error"] assert isinstance(error, int), "'error' must be of type int" assert error >= 0 dt = entry["datetime"] assert isinstance( dt, datetime.datetime), "'dt' must be of type datetime" msg = entry["message"] assert isinstance(msg, str), "'msg' must be of type str" #assert 0 @pytest.mark.run_if_connected @pytest.mark.usefixtures("reconnect") def test_get_fault_list_with_index_raises_IOError(self, hthp: HtHeatpump): with pytest.raises(IOError): hthp.get_fault_list(-1) # index=-1 is invalid with pytest.raises(IOError): hthp.get_fault_list(9999) # index=9999 is invalid #assert 0 @pytest.mark.run_if_connected @pytest.mark.usefixtures("reconnect") def test_get_fault_list_with_indices(self, hthp: HtHeatpump): size = hthp.get_fault_list_size() for cnt in range(size + 1): indices = random.sample(range(size), cnt) fault_list = hthp.get_fault_list(*indices) assert isinstance(fault_list, list), "'fault_list' must be of type list" for entry in fault_list: assert isinstance(entry, dict), "'entry' must be of type dict" index = entry["index"] assert isinstance(index, int), "'index' must be of type int" assert 0 <= index < hthp.get_fault_list_size() error = entry["error"] assert isinstance(error, int), "'error' must be of type int" assert error >= 0 dt = entry["datetime"] assert isinstance( dt, datetime.datetime), "'dt' must be of type datetime" msg = entry["message"] assert isinstance(msg, str), "'msg' must be of type str" #assert 0 @pytest.mark.run_if_connected @pytest.mark.usefixtures("reconnect") @pytest.mark.parametrize("name, param", HtParams.items()) def test_get_param(self, hthp: HtHeatpump, name: str, param: HtParam): value = hthp.get_param(name) assert value is not None, "'value' must not be None" assert param.in_limits(value) #assert 0 def test_get_param_raises_KeyError(self, cmdopt_device: str, cmdopt_baudrate: int): hp = HtHeatpump(device=cmdopt_device, baudrate=cmdopt_baudrate) with pytest.raises(KeyError): hp.get_param("BlaBlaBla") #assert 0 @pytest.mark.run_if_connected @pytest.mark.usefixtures("reconnect") @pytest.mark.parametrize("name, param", HtParams.items()) def test_set_param(self, hthp: HtHeatpump, name: str, param: HtParam): pass # TODO #assert 0 def test_set_param_raises_KeyError(self, cmdopt_device: str, cmdopt_baudrate: int): hp = HtHeatpump(device=cmdopt_device, baudrate=cmdopt_baudrate) with pytest.raises(KeyError): hp.set_param("BlaBlaBla", 123) #assert 0 @pytest.mark.parametrize( "name, param", [(name, param) for name, param in HtParams.items() if param.data_type in (HtDataTypes.INT, HtDataTypes.FLOAT)]) def test_set_param_raises_ValueError(self, cmdopt_device: str, cmdopt_baudrate: int, name: str, param: HtParam): hp = HtHeatpump(device=cmdopt_device, baudrate=cmdopt_baudrate) with pytest.raises(ValueError): hp.set_param(name, param.min_val - 1, ignore_limits=False) # type: ignore with pytest.raises(ValueError): hp.set_param(name, param.max_val + 1, ignore_limits=False) # type: ignore #assert 0 @pytest.mark.run_if_connected @pytest.mark.usefixtures("reconnect") def test_in_error(self, hthp: HtHeatpump): in_error = hthp.in_error assert isinstance(in_error, bool), "'in_error' must be of type bool" assert in_error == hthp.get_param("Stoerung") #assert 0 @pytest.mark.run_if_connected @pytest.mark.usefixtures("reconnect") def test_query(self, hthp: HtHeatpump): values = hthp.query() # { "HKR Soll_Raum": 21.0, # "Stoerung": False, # "Temp. Aussen": 8.8, # # ... # } assert isinstance(values, dict), "'values' must be of type dict" assert len(values) == len(HtParams) for n, v in values.items(): assert n in HtParams assert v is not None assert HtParams[n].in_limits(v) #assert 0 @pytest.mark.run_if_connected @pytest.mark.usefixtures("reconnect") @pytest.mark.parametrize("names", [ random.sample(HtParams.keys(), cnt) for cnt in range(len(HtParams) + 1) ]) def test_query_with_names(self, hthp: HtHeatpump, names: List[str]): values = hthp.query(*names) # { "HKR Soll_Raum": 21.0, # "Stoerung": False, # "Temp. Aussen": 8.8, # # ... # } assert isinstance(values, dict), "'values' must be of type dict" assert not names or len(values) == len(set(names)) for n, v in values.items(): assert n in HtParams assert not names or n in names assert v is not None assert HtParams[n].in_limits(v) #assert 0 @pytest.mark.run_if_connected @pytest.mark.usefixtures("reconnect") def test_fast_query(self, hthp: HtHeatpump): values = hthp.fast_query() assert isinstance(values, dict), "'values' must be of type dict" assert len(values) == len(HtParams.of_type("MP")) for n, v in values.items(): assert n in HtParams assert v is not None assert HtParams[n].in_limits(v) #assert 0 @pytest.mark.run_if_connected @pytest.mark.usefixtures("reconnect") @pytest.mark.parametrize("names", [ random.sample(HtParams.of_type("MP").keys(), cnt) for cnt in range(len(HtParams.of_type("MP")) + 1) ]) def test_fast_query_with_names(self, hthp: HtHeatpump, names: List[str]): values = hthp.fast_query(*names) assert isinstance(values, dict), "'values' must be of type dict" assert not names or len(values) == len(set(names)) for n, v in values.items(): assert n in HtParams assert not names or n in names assert v is not None assert HtParams[n].in_limits(v) #assert 0 def test_fast_query_with_names_raises_KeyError(self, cmdopt_device: str, cmdopt_baudrate: int): hp = HtHeatpump(device=cmdopt_device, baudrate=cmdopt_baudrate) with pytest.raises(KeyError): hp.fast_query("BlaBlaBla") #assert 0 @pytest.mark.parametrize("names", [ random.sample(HtParams.of_type("SP").keys(), cnt) for cnt in range(1, len(HtParams.of_type("SP")) + 1) ]) def test_fast_query_with_names_raises_ValueError(self, cmdopt_device: str, cmdopt_baudrate: int, names: List[str]): hp = HtHeatpump(device=cmdopt_device, baudrate=cmdopt_baudrate) with pytest.raises(ValueError): hp.fast_query(*names) #assert 0 @pytest.mark.run_if_connected @pytest.mark.usefixtures("reconnect") def test_get_time_progs(self, hthp: HtHeatpump): time_progs = hthp.get_time_progs() assert isinstance(time_progs, List), "'time_progs' must be of type list" assert len(time_progs) > 0 assert all( [isinstance(time_prog, TimeProgram) for time_prog in time_progs]) #assert 0 @pytest.mark.run_if_connected @pytest.mark.usefixtures("reconnect") @pytest.mark.parametrize( "index", range(5)) # TODO range(5) -> range(len(hthp.get_time_progs())) def test_get_time_prog(self, hthp: HtHeatpump, index: int): time_prog = hthp.get_time_prog(index, with_entries=False) assert isinstance( time_prog, TimeProgram), "'time_prog' must be of type TimeProgram" time_prog = hthp.get_time_prog(index, with_entries=True) assert isinstance( time_prog, TimeProgram), "'time_prog' must be of type TimeProgram" #assert 0 @pytest.mark.run_if_connected @pytest.mark.usefixtures("reconnect") @pytest.mark.parametrize("index", [-1, 5]) def test_get_time_prog_raises_IOError(self, hthp: HtHeatpump, index: int): with pytest.raises(IOError): hthp.get_time_prog(index, with_entries=False) with pytest.raises(IOError): hthp.get_time_prog(index, with_entries=True) #assert 0 @pytest.mark.run_if_connected @pytest.mark.usefixtures("reconnect") @pytest.mark.parametrize( "index, day, num", [ # for ALL time program entries (index, day, num) for index in range(5) for day in range(7) for num in range(7) ]) def test_get_time_prog_entry(self, hthp: HtHeatpump, index: int, day: int, num: int): entry = hthp.get_time_prog_entry(index, day, num) assert isinstance( entry, TimeProgEntry), "'entry' must be of type TimeProgEntry" #assert 0 @pytest.mark.run_if_connected @pytest.mark.usefixtures("reconnect") @pytest.mark.parametrize( "index, day, num", [ (5, 0, 0), # index=5 is invalid (0, 7, 0), # day=7 is invalid (0, 0, 7), # num=7 is invalid ]) def test_get_time_prog_entry_raises_IOError(self, hthp: HtHeatpump, index: int, day: int, num: int): with pytest.raises(IOError): hthp.get_time_prog_entry(index, day, num) #assert 0 @pytest.mark.run_if_connected @pytest.mark.usefixtures("reconnect") def test_set_time_prog_entry(self, hthp: HtHeatpump): pass # TODO #assert 0 @pytest.mark.run_if_connected @pytest.mark.usefixtures("reconnect") def test_set_time_prog(self, hthp: HtHeatpump): pass # TODO
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)