397 lines
17 KiB
Python
397 lines
17 KiB
Python
|
import colored
|
||
|
import config
|
||
|
import inspect
|
||
|
import simulation.devices as devices
|
||
|
import time
|
||
|
|
||
|
|
||
|
DT_TOGGLE = 0.3
|
||
|
|
||
|
|
||
|
TEST_FULL = 'full'
|
||
|
TEST_SMOKE = 'smoke'
|
||
|
#
|
||
|
COLOR_SUCCESS = colored.fg("light_green")
|
||
|
COLOR_FAIL = colored.fg("light_red")
|
||
|
|
||
|
|
||
|
class test_smarthome(object):
|
||
|
def __init__(self, rooms):
|
||
|
# add testcases for switching devices
|
||
|
for name in rooms.getmembers():
|
||
|
obj = rooms.getobjbyname(name)
|
||
|
if obj.__class__.__name__ == "videv_light":
|
||
|
common_name = '.'.join(name.split('.')[:-1]) + '.' + name.split('.')[-1][6:]
|
||
|
try:
|
||
|
li_device = rooms.getobjbyname(common_name + '_zigbee') if obj.enable_brightness or obj.enable_color_temp else None
|
||
|
except AttributeError:
|
||
|
li_device = rooms.getobjbyname(common_name + '_zigbee_1') if obj.enable_brightness or obj.enable_color_temp else None
|
||
|
try:
|
||
|
sw_device = rooms.getobjbyname(common_name) if obj.enable_state else None
|
||
|
except AttributeError:
|
||
|
# must be a device without switching device
|
||
|
sw_device = li_device
|
||
|
setattr(self, common_name.replace('.', '_'), testcase_light(obj, sw_device, li_device))
|
||
|
# add testcases for heating devices
|
||
|
for name in rooms.getmembers():
|
||
|
obj = rooms.getobjbyname(name)
|
||
|
if obj.__class__.__name__ == "videv_heating":
|
||
|
common_name = '.'.join(name.split('.')[:-1]) + '.' + name.split('.')[-1][6:]
|
||
|
heat_device = rooms.getobjbyname(common_name + '_valve')
|
||
|
setattr(self, common_name.replace('.', '_'), testcase_heating(obj, heat_device))
|
||
|
# synchronisation
|
||
|
self.gfw_dirk_cd_player_amplifier_sync = testcase_synchronisation(
|
||
|
rooms.gfw.dirk.cd_player, None, None,
|
||
|
rooms.gfw.dirk.amplifier)
|
||
|
self.gfw_floor_main_light_sync = testcase_synchronisation(
|
||
|
rooms.gfw.floor.main_light, rooms.gfw.floor.videv_main_light, rooms.gfw.floor.videv_main_light,
|
||
|
rooms.gfw.floor.main_light_zigbee_1, rooms.gfw.floor.main_light_zigbee_2
|
||
|
)
|
||
|
self.ffe_diningroom_main_light_floor_lamp_sync = testcase_synchronisation(
|
||
|
rooms.ffe.diningroom.main_light, None, None,
|
||
|
rooms.ffe.diningroom.floor_lamp)
|
||
|
self.ffe_livingroom_main_light_floor_lamp_sync = testcase_synchronisation(
|
||
|
rooms.ffe.livingroom.main_light, rooms.ffe.livingroom.videv_floor_lamp, rooms.ffe.livingroom.videv_floor_lamp,
|
||
|
*[getattr(rooms.ffe.livingroom, "floor_lamp_zigbee_%d" % i) for i in range(1, 7)]
|
||
|
)
|
||
|
# add test collection
|
||
|
self.all = test_collection(self)
|
||
|
|
||
|
def getmembers(self, prefix=''):
|
||
|
rv = []
|
||
|
for name, obj in inspect.getmembers(self):
|
||
|
if prefix:
|
||
|
full_name = prefix + '.' + name
|
||
|
else:
|
||
|
full_name = name
|
||
|
if not name.startswith('_'):
|
||
|
try:
|
||
|
if obj.__class__.__bases__[0].__name__ == "testcase" or obj.__class__.__name__ == "test_collection":
|
||
|
rv.append(full_name)
|
||
|
else:
|
||
|
rv.extend(obj.getmembers(full_name))
|
||
|
except AttributeError:
|
||
|
pass
|
||
|
return rv
|
||
|
|
||
|
def getobjbyname(self, name):
|
||
|
if name.startswith("test."):
|
||
|
name = name[5:]
|
||
|
obj = self
|
||
|
for subname in name.split('.'):
|
||
|
obj = getattr(obj, subname)
|
||
|
return obj
|
||
|
|
||
|
def command(self, full_command):
|
||
|
try:
|
||
|
parameter = " " + full_command.split(' ')[1]
|
||
|
except IndexError:
|
||
|
parameter = ""
|
||
|
command = full_command.split(' ')[0].split('.')[-1] + parameter
|
||
|
device_name = '.'.join(full_command.split(' ')[0].split('.')[:-1])
|
||
|
self.getobjbyname(device_name).command(command)
|
||
|
|
||
|
|
||
|
class test_result_base(object):
|
||
|
def __init__(self):
|
||
|
self.__init_test_counters__()
|
||
|
|
||
|
def __init_test_counters__(self):
|
||
|
self.test_counter = 0
|
||
|
self.success_tests = 0
|
||
|
self.failed_tests = 0
|
||
|
|
||
|
def statistic(self):
|
||
|
return (self.test_counter, self.success_tests, self.failed_tests)
|
||
|
|
||
|
def print_statistic(self):
|
||
|
color = COLOR_SUCCESS if self.test_counter == self.success_tests else COLOR_FAIL
|
||
|
print(color + "*** SUCCESS: (%4d/%4d) FAIL: (%4d/%4d) ***\n" % (self.success_tests,
|
||
|
self.test_counter, self.failed_tests, self.test_counter) + colored.attr("reset"))
|
||
|
|
||
|
|
||
|
class test_collection(test_result_base):
|
||
|
def __init__(self, test_instance):
|
||
|
super().__init__()
|
||
|
self.test_instance = test_instance
|
||
|
|
||
|
def capabilities(self):
|
||
|
return [TEST_FULL, TEST_SMOKE]
|
||
|
|
||
|
def command(self, command):
|
||
|
self.__init_test_counters__()
|
||
|
for member in self.test_instance.getmembers():
|
||
|
obj = self.test_instance.getobjbyname(member)
|
||
|
if id(obj) != id(self):
|
||
|
obj.test_all(command)
|
||
|
num, suc, fail = obj.statistic()
|
||
|
self.test_counter += num
|
||
|
self.success_tests += suc
|
||
|
self.failed_tests += fail
|
||
|
self.print_statistic()
|
||
|
|
||
|
|
||
|
class testcase(test_result_base):
|
||
|
def __init__(self):
|
||
|
super().__init__()
|
||
|
self.__test_list__ = []
|
||
|
|
||
|
def capabilities(self):
|
||
|
if len(self.__test_list__) > 0 and not 'test_all' in self.__test_list__:
|
||
|
self.__test_list__.append('test_all')
|
||
|
self.__test_list__.sort()
|
||
|
return self.__test_list__
|
||
|
|
||
|
def test_all(self, test=TEST_FULL):
|
||
|
test_counter = 0
|
||
|
success_tests = 0
|
||
|
failed_tests = 0
|
||
|
for tc_name in self.capabilities():
|
||
|
if tc_name != "test_all":
|
||
|
self.command(tc_name, test)
|
||
|
test_counter += self.test_counter
|
||
|
success_tests += self.success_tests
|
||
|
failed_tests += self.failed_tests
|
||
|
self.test_counter = test_counter
|
||
|
self.success_tests = success_tests
|
||
|
self.failed_tests = failed_tests
|
||
|
|
||
|
def command(self, command, test=TEST_FULL):
|
||
|
self.__init_test_counters__()
|
||
|
tc = getattr(self, command)
|
||
|
self.__init_test_counters__()
|
||
|
tc(test)
|
||
|
self.print_statistic()
|
||
|
|
||
|
def heading(self, desciption):
|
||
|
print(desciption)
|
||
|
|
||
|
def sub_heading(self, desciption):
|
||
|
print(2 * " " + desciption)
|
||
|
|
||
|
def result(self, desciption, success):
|
||
|
self.test_counter += 1
|
||
|
if success:
|
||
|
self.success_tests += 1
|
||
|
else:
|
||
|
self.failed_tests += 1
|
||
|
print(4 * " " + ("SUCCESS - " if success else "FAIL - ") + desciption)
|
||
|
|
||
|
|
||
|
class testcase_light(testcase):
|
||
|
def __init__(self, videv, sw_device, li_device):
|
||
|
self.videv = videv
|
||
|
self.sw_device = sw_device
|
||
|
self.li_device = li_device
|
||
|
self.__test_list__ = []
|
||
|
if self.videv.enable_state:
|
||
|
self.__test_list__.append('test_power_on_off')
|
||
|
if self.videv.enable_brightness:
|
||
|
self.__test_list__.append('test_brightness')
|
||
|
if self.videv.enable_color_temp:
|
||
|
self.__test_list__.append('test_color_temp')
|
||
|
|
||
|
def test_power_on_off(self, test=TEST_FULL):
|
||
|
self.heading("Power On/ Off test (%s)" % self.videv.topic)
|
||
|
#
|
||
|
sw_state = self.sw_device.get(self.sw_device.KEY_OUTPUT_0)
|
||
|
#
|
||
|
for i in range(0, 2):
|
||
|
self.sub_heading("State change of switching device")
|
||
|
#
|
||
|
self.sw_device.set(self.sw_device.KEY_OUTPUT_0, not self.sw_device.get(self.sw_device.KEY_OUTPUT_0))
|
||
|
time.sleep(DT_TOGGLE)
|
||
|
self.result("Virtual device state after Switch on by switching device", sw_state != self.videv.get(self.videv.KEY_OUTPUT_0))
|
||
|
self.result("Switching device state after Switch on by switching device",
|
||
|
sw_state != self.sw_device.get(self.sw_device.KEY_OUTPUT_0))
|
||
|
|
||
|
self.sub_heading("State change of virtual device")
|
||
|
#
|
||
|
self.videv.set(self.videv.KEY_OUTPUT_0, not self.videv.get(self.videv.KEY_OUTPUT_0))
|
||
|
time.sleep(DT_TOGGLE)
|
||
|
self.result("Virtual device state after Switch off by virtual device", sw_state == self.videv.get(self.videv.KEY_OUTPUT_0))
|
||
|
self.result("Switching device state after Switch on by switching device",
|
||
|
sw_state == self.sw_device.get(self.sw_device.KEY_OUTPUT_0))
|
||
|
|
||
|
def test_brightness(self, test=TEST_FULL):
|
||
|
self.heading("Brightness test (%s)" % self.videv.topic)
|
||
|
#
|
||
|
br_state = self.li_device.get(self.li_device.KEY_BRIGHTNESS)
|
||
|
delta = -15 if br_state > 50 else 15
|
||
|
|
||
|
self.sw_device.set(self.sw_device.KEY_OUTPUT_0, True)
|
||
|
time.sleep(DT_TOGGLE)
|
||
|
|
||
|
for i in range(0, 2):
|
||
|
self.sub_heading("Brightness change by light device")
|
||
|
#
|
||
|
self.li_device.set(self.li_device.KEY_BRIGHTNESS, br_state + delta)
|
||
|
time.sleep(DT_TOGGLE)
|
||
|
self.result("Virtual device state after setting brightness by light device",
|
||
|
br_state + delta == self.videv.get(self.videv.KEY_BRIGHTNESS))
|
||
|
self.result("Light device state after setting brightness by light device", br_state +
|
||
|
delta == self.li_device.get(self.li_device.KEY_BRIGHTNESS))
|
||
|
|
||
|
self.sub_heading("Brightness change by virtual device")
|
||
|
#
|
||
|
self.videv.set(self.videv.KEY_BRIGHTNESS, br_state)
|
||
|
time.sleep(DT_TOGGLE)
|
||
|
self.result("Virtual device state after setting brightness by light device", br_state == self.videv.get(self.videv.KEY_BRIGHTNESS))
|
||
|
self.result("Light device state after setting brightness by light device",
|
||
|
br_state == self.li_device.get(self.li_device.KEY_BRIGHTNESS))
|
||
|
|
||
|
self.sw_device.set(self.sw_device.KEY_OUTPUT_0, False)
|
||
|
time.sleep(DT_TOGGLE)
|
||
|
|
||
|
def test_color_temp(self, test=TEST_FULL):
|
||
|
self.heading("Color temperature test (%s)" % self.videv.topic)
|
||
|
#
|
||
|
ct_state = self.li_device.get(self.li_device.KEY_COLOR_TEMP)
|
||
|
delta = -3 if ct_state > 5 else 3
|
||
|
|
||
|
self.sw_device.set(self.sw_device.KEY_OUTPUT_0, True)
|
||
|
time.sleep(DT_TOGGLE)
|
||
|
|
||
|
for i in range(0, 2):
|
||
|
self.sub_heading("Color temperature change by light device")
|
||
|
#
|
||
|
self.li_device.set(self.li_device.KEY_COLOR_TEMP, ct_state + delta)
|
||
|
time.sleep(DT_TOGGLE)
|
||
|
self.result("Virtual device state after setting color temperature by light device",
|
||
|
ct_state + delta == self.videv.get(self.videv.KEY_COLOR_TEMP))
|
||
|
self.result("Light device state after setting color temperature by light device", ct_state +
|
||
|
delta == self.li_device.get(self.li_device.KEY_COLOR_TEMP))
|
||
|
|
||
|
self.sub_heading("Color temperature change by virtual device")
|
||
|
#
|
||
|
self.videv.set(self.videv.KEY_COLOR_TEMP, ct_state)
|
||
|
time.sleep(DT_TOGGLE)
|
||
|
self.result("Virtual device state after setting color temperature by light device",
|
||
|
ct_state == self.videv.get(self.videv.KEY_COLOR_TEMP))
|
||
|
self.result("Light device state after setting color temperature by light device",
|
||
|
ct_state == self.li_device.get(self.li_device.KEY_COLOR_TEMP))
|
||
|
|
||
|
self.sw_device.set(self.sw_device.KEY_OUTPUT_0, False)
|
||
|
time.sleep(DT_TOGGLE)
|
||
|
|
||
|
|
||
|
class testcase_synchronisation(testcase):
|
||
|
def __init__(self, sw_master, br_master, ct_master, *follower):
|
||
|
super().__init__()
|
||
|
self.sw_master = sw_master
|
||
|
self.br_master = br_master
|
||
|
self.ct_master = ct_master
|
||
|
self.follower = follower
|
||
|
self.__test_list__ = []
|
||
|
if sw_master is not None:
|
||
|
self.__test_list__.append('test_power_on_off_sync')
|
||
|
if br_master is not None:
|
||
|
self.__test_list__.append('test_brightness_sync')
|
||
|
|
||
|
def test_power_on_off_sync(self, test=TEST_FULL):
|
||
|
self.heading("Power On/ Off sychronisation test")
|
||
|
#
|
||
|
# set sw_master to slave state as precondition
|
||
|
f_state = self.follower[0].get(self.follower[0].KEY_OUTPUT_0)
|
||
|
self.sw_master.set(self.sw_master.KEY_OUTPUT_0, f_state)
|
||
|
time.sleep(DT_TOGGLE)
|
||
|
for i in range(0, 2):
|
||
|
self.sub_heading("State change of sw_master device")
|
||
|
#
|
||
|
self.sw_master.set(self.sw_master.KEY_OUTPUT_0, not f_state)
|
||
|
time.sleep(DT_TOGGLE)
|
||
|
f_state = not f_state
|
||
|
for fo in self.follower:
|
||
|
self.result("Follower device state after switching (%s)" % fo.topic,
|
||
|
f_state == fo.get(fo.KEY_OUTPUT_0))
|
||
|
|
||
|
def test_brightness_sync(self, test=TEST_FULL):
|
||
|
self.heading("Power On/ Off sychronisation test")
|
||
|
#
|
||
|
# set precondition
|
||
|
sw_state = self.sw_master.get(self.sw_master.KEY_OUTPUT_0)
|
||
|
self.sw_master.set(self.sw_master.KEY_OUTPUT_0, True)
|
||
|
time.sleep(DT_TOGGLE)
|
||
|
|
||
|
target = self.follower[0].get(self.follower[0].KEY_BRIGHTNESS)
|
||
|
delta = 15 if target < 50 else -15
|
||
|
for i in range(0, 2):
|
||
|
target = target + delta
|
||
|
self.sub_heading("State change of br_master device")
|
||
|
#
|
||
|
self.br_master.set(self.br_master.KEY_BRIGHTNESS, target)
|
||
|
time.sleep(DT_TOGGLE)
|
||
|
for fo in self.follower:
|
||
|
self.result("Follower device brightness after change (%s)" % fo.topic,
|
||
|
target == fo.get(fo.KEY_BRIGHTNESS))
|
||
|
delta = -delta
|
||
|
|
||
|
# reset changes of precondition
|
||
|
self.sw_master.set(self.sw_master.KEY_OUTPUT_0, sw_state)
|
||
|
time.sleep(DT_TOGGLE)
|
||
|
|
||
|
|
||
|
class testcase_heating(testcase):
|
||
|
def __init__(self, videv, valve):
|
||
|
self.__videv__ = videv
|
||
|
self.__valve__ = valve
|
||
|
self.__default_temperature__ = config.DEFAULT_TEMPERATURE.get(self.__valve__.topic)
|
||
|
self.__test_list__ = ["test_user_temperature_setpoint", "test_default_temperature", ]
|
||
|
|
||
|
def test_user_temperature_setpoint(self, test=TEST_FULL):
|
||
|
self.heading("User temperature setpoint test (%s)" % self.__videv__.topic)
|
||
|
#
|
||
|
mtemp = round(self.__valve__.TEMP_RANGE[0] + (self.__valve__.TEMP_RANGE[1] - self.__valve__.TEMP_RANGE[0]) / 2, 1)
|
||
|
setp = self.__valve__.get(self.__valve__.KEY_TEMPERATURE_SETPOINT)
|
||
|
delta = 5 if setp < mtemp else -5
|
||
|
|
||
|
for i in range(0, 2):
|
||
|
self.sub_heading("Setpoint change by valve device")
|
||
|
#
|
||
|
self.__valve__.set(self.__valve__.KEY_TEMPERATURE_SETPOINT, setp + delta)
|
||
|
time.sleep(DT_TOGGLE)
|
||
|
self.result("Virtual device valve temperature after setting temperature by valve device",
|
||
|
setp + delta == self.__videv__.get(self.__videv__.KEY_VALVE_TEMPERATURE_SETPOINT))
|
||
|
self.result("Virtual device user temperature after setting temperature by valve device",
|
||
|
setp + delta == self.__videv__.get(self.__videv__.KEY_USER_TEMPERATURE_SETPOINT))
|
||
|
|
||
|
self.sub_heading("Setpoint change by videv device")
|
||
|
#
|
||
|
self.__videv__.set(self.__videv__.KEY_USER_TEMPERATURE_SETPOINT, setp)
|
||
|
time.sleep(DT_TOGGLE)
|
||
|
self.result("Valve device temperature setpoint after setting temperature by videv device",
|
||
|
setp == self.__valve__.get(self.__valve__.KEY_TEMPERATURE_SETPOINT))
|
||
|
self.result("Virtual device valve temperature after setting temperature by videv device",
|
||
|
setp == self.__videv__.get(self.__videv__.KEY_VALVE_TEMPERATURE_SETPOINT))
|
||
|
|
||
|
def test_default_temperature(self, test=TEST_FULL):
|
||
|
self.heading("Default temperature setpoint test (%s)" % self.__videv__.topic)
|
||
|
#
|
||
|
dtemp = config.DEFAULT_TEMPERATURE.get(self.__valve__.topic)
|
||
|
mtemp = round(self.__valve__.TEMP_RANGE[0] + (self.__valve__.TEMP_RANGE[1] - self.__valve__.TEMP_RANGE[0]) / 2, 1)
|
||
|
ptemp = dtemp + (5 if dtemp < mtemp else -5)
|
||
|
|
||
|
self.sub_heading("Setting setpoint to a value unequal default as precondition")
|
||
|
self.__valve__.set(self.__valve__.KEY_TEMPERATURE_SETPOINT, ptemp)
|
||
|
time.sleep(DT_TOGGLE)
|
||
|
self.result("Valve device temperature setpoint after setting precondition temperature",
|
||
|
ptemp == self.__valve__.get(self.__valve__.KEY_TEMPERATURE_SETPOINT))
|
||
|
|
||
|
self.sub_heading("Triggering default temperature by videv device")
|
||
|
self.__videv__.set(self.__videv__.KEY_SET_DEFAULT_TEMPERATURE, None)
|
||
|
time.sleep(DT_TOGGLE)
|
||
|
self.result("Valve device temperature setpoint after setting default temperature",
|
||
|
dtemp == self.__valve__.get(self.__valve__.KEY_TEMPERATURE_SETPOINT))
|
||
|
|
||
|
def test_summer_mode(self, test=TEST_FULL):
|
||
|
pass
|
||
|
|
||
|
def test_away_mode(self, test=TEST_FULL):
|
||
|
pass
|
||
|
|
||
|
def test_boost_mode(self, test=TEST_FULL):
|
||
|
pass
|
||
|
if test == TEST_FULL:
|
||
|
# test boost timer
|
||
|
pass
|