def test_fake(monkeypatch, setup_test): with freeze_time(parse("2000-01-01 12:00:00")) as fdt: global FDT FDT = fdt monkeypatch.setattr(time, 'sleep', sleepless) c = Camera(sw_cam=True) c.file_by_date = False c._interval = timedelta(minutes=10) run_until(c, fdt, today_at(13)) assert len(c.recent_images) == 6 + 1 # fencepost images = sorted(glob(os.path.join(c.tmv_root, "2000-01-01T*"))) assert len(images) == 6 + 1 # fencepost # run 13:00 - 14:00 with switch AUTO c.mode_button.value = AUTO run_until(c, fdt, today_at(14)) assert c.active_timer.active() # active images = sorted(glob(os.path.join(c.tmv_root, "2000-01-01T*"))) assert len(images) == 6 + 1 + 6 # one hour more of 6 photos per hour # run 14:00 - 15:00 with switch ON c.active_timer = Timed(datetime.time(6, 0, 0), datetime.time(7, 0, 0)) c.mode_button.value = ON run_until(c, fdt, today_at(15)) assert not c.active_timer.active() # not active - but overridden by switch images = sorted(glob(os.path.join(c.tmv_root, "2000-01-01T*"))) # one hour more of 6 photos per hour assert len(images) == 6 + 1 + 6 + 6 assert Path("./latest-image.jpg").is_file()
def test_Sensor_lookups(): c = Camera(sw_cam=True) c.active_timer = tmv.camera.ActiveTimes.factory( on='dim', off='dark', camera=c) c.light_sensor._current_level = LightLevel.LIGHT assert c.active_timer.camera_active() c = Camera(sw_cam=True) ss = tmv.camera.ActiveTimes.factory(on='dim', off='dark', camera=c) c.light_sensor._current_level = LightLevel.DARK # Active, as sensor will operate assert ss.active() is True # But could power off if camera not required (it's DARK) assert timedelta(minutes=59) <= ( ss.waketime() - dt.now()) <= timedelta(minutes=61) c.light_sensor._current_level = LightLevel.DIM # Still active assert ss.active() # But can't power off for long (camera is active) assert ss.waketime() <= dt.now() c.light_sensor._current_level = LightLevel.LIGHT assert ss.waketime() <= dt.now() c.light_sensor._current_level = LightLevel.DIM assert ss.waketime() <= dt.now() c.light_sensor._current_level = LightLevel.DARK # active, but only the sensor assert ss.active() assert timedelta(minutes=59) <= ( ss.waketime() - dt.now()) <= timedelta(minutes=61) # c.light_sensor._current_level = LightLevel.LIGHT # ON when DIM, OFF when DARK, should be ON when light assert ss.active()
def test_Sensor(monkeypatch, setup_test): with freeze_time(parse("2000-01-01 00:00:00")) as fdt: global FDT FDT = fdt monkeypatch.setattr(time, 'sleep', sleepless) c = Camera(sw_cam=True) c.save_images = True c.light_sensor.freq = timedelta(minutes=20) c.light_sensor.max_age = timedelta(hours=1) c.configs(""" [location] city = "Brisbane" [camera] interval = 300 # test ON at first light, then off when dark (i.e. all day) on = 'light' off = 'dim' camera_inactive_action = 'WAIT' """) c.mode_button.value = AUTO reset_camera = deepcopy(c) # a copy of the camera after it starts run_until(c, fdt, tomorrow_at(12), reset_camera) run_until(c, fdt, today_at(18, 00), reset_camera) run_until(c, fdt, today_at(23, 59), reset_camera) run_until(c, fdt, tomorrow_at(9, 00), reset_camera) reset_camera.run(1) assert reset_camera.active_timer.light_sensor.level == LightLevel.LIGHT
def test_low_light_sense(monkeypatch, setup_test): with freeze_time(parse("2000-01-01 00:00:00")) as fdt: global FDT FDT = fdt monkeypatch.setattr(time, 'sleep', sleepless) c = Camera(sw_cam=True) c.file_by_date = False c._interval = timedelta(hours=1) c.light_sensor.light = 0.6 c.light_sensor.dark = 0.1 c.light_sensor.freq = timedelta(minutes=10) c.light_sensor.max_age = timedelta(minutes=60) assert c.light_sensor.level == LightLevel.LIGHT # starts LIGHT by default run_until(c, fdt, today_at(3)) assert c.light_sensor.level == LightLevel.DARK run_until(c, fdt, today_at(10)) assert c.light_sensor.level == LightLevel.DIM run_until(c, fdt, today_at(12)) assert c.light_sensor.level == LightLevel.LIGHT run_until(c, fdt, today_at(16, 30)) assert c.light_sensor.level == LightLevel.DIM run_until(c, fdt, today_at(23)) assert c.light_sensor.level == LightLevel.DARK images = glob(os.path.join(c.tmv_root, "2000-01-01T*")) assert len(images) == 24
def test_latest_image(setup_test): cf = """ [camera] tmv_root = "." """ c = Camera(sw_cam=True) c.configs(cf) cwd = Path(os.getcwd()) assert (cwd / "latest-image.jpg").absolute() == c.latest_image.absolute()
def test_location(): cf = """ [camera] on = 'dawn' off = 'dusk' """ # no location: fail c = Camera(sw_cam=True) with pytest.raises(tmv.camera.ConfigError): c.configs(cf) cf = """ [camera] city = 'Brisbane' on = 'dawn' off = 'dusk' """ # location: ok c.configs(cf) cf = """ [camera] city = 'auto' on = 'dawn' off = 'dusk' """ # no location: fail with pytest.raises(NotImplementedError): c.configs(cf)
def test_camera_inactive_action(monkeypatch, setup_test): with freeze_time(parse("2000-01-01 12:00:00")) as fdt: global FDT FDT = fdt monkeypatch.setattr(time, 'sleep', sleepless) c = Camera(sw_cam=True) c.mode_button.value = AUTO c.save_images = False c.configs(""" [camera] interval = 900 # 15 minutes on = 09:00:00 off = 13:00:00 camera_inactive_action = 'EXCEPTION' """) c._camera = FakePiCamera() c.mode_button.value = AUTO with pytest.raises(PowerOff): run_until(c, fdt, today_at(18)) c.configs(""" [camera] on = 09:00:00 off = 13:00:00 camera_inactive_action = 'WAIT' """) run_until(c, fdt, tomorrow_at(18)) # no raise
def test_speeds(setup_test): """ Test interval change with speed button""" c = Camera(sw_cam=True) assert c._interval == timedelta(seconds=60) cf = """ [camera] interval = 100 """ c.configs(cf) assert c.interval == timedelta(seconds=100) c.speed_button.value = SLOW assert c.interval == timedelta(seconds=100 * SPEED_MULTIPLIER) c.speed_button.value = FAST assert c.interval == timedelta(seconds=100 / SPEED_MULTIPLIER)
def test_config(monkeypatch, setup_test): with freeze_time(parse("2000-01-01 00:00:00")) as fdt: global FDT FDT = fdt c = Camera(sw_cam=True) c.tmv_root = "./test_config/" cf = """ [location] city = "Brisbane" [camera] off = 07:00:00 on = 18:00:00 [camera.picam.LIGHT] id = "Custom day config at 800" iso = 800 exposure_mode = "auto" resolution = "800x600" [camera.picam.DIM] id = "CUSTOM-DIM" framerate = 1 iso = 0 exposure_mode = "night" resolution = "800x600" [camera.picam.DARK] id = "CUSTOM-NIGHTY" framerate = 1 iso = 1600 shutter_speed = 1000000 exposure_mode = "verylong" resolution = "800x600" """ c.configs(cf) # default assert c.picam[LightLevel.LIGHT.name]['exposure_mode'] == 'auto' assert c.picam[LightLevel.LIGHT.name]['resolution'] == '800x600' # new one assert c.picam[LightLevel.LIGHT.name]['iso'] == 800 c._camera = FakePiCamera() # fake sleeping monkeypatch.setattr(time, 'sleep', sleepless) c.run(3) # should have clicked over to DARK. Configured a special iso for DARK in toml. assert c.picam[c.light_sensor.level.name]['iso'] == 1600 c.run(1)
def test_image_stats_2(): """ Test max_age =0 boundary case""" # pixel_avg looks # 2020-04-05T14-31-20.jpg .29 light 0 # 2020-04-05T15-24-20.jpg .13 light 1 # 2020-04-05T16-24-20.jpg .08 dim 2 # 2020-04-05T17-24-20.jpg .04 dim 3 # 2020-04-05T18-24-20.jpg .01 dim 4 # thresholds: light > 0.10 # dark < 0.01 with freeze_time(dateutil.parser.parse("2020-04-05T20:00:00")): image_files = [] rex = re.compile("^2020-04-05T.*") for r, ds, fs in os.walk(TEST_DATA / "camera_images"): print(ds) image_files = [os.path.join(r, f) for f in fs if rex.match(f) is not None] break # no deeper assert len(image_files) == 5 cam = Camera(sw_cam=True) cam.light_sensor.max_age = timedelta(seconds=0) cam.light_sensor.dark = 0.0 # make sure they are DIM assert cam.light_sensor.level == tmv.camera.LightLevel.LIGHT for f in sorted(image_files): cam.light_sensor.add_reading( tmv.util.str2dt(f), calc_pixel_average(f)) print("length:{}".format(len(cam.light_sensor._levels))) assert cam.light_sensor.level == tmv.camera.LightLevel.DIM assert len(cam.light_sensor._levels) == 0
def test_Timed_capture(monkeypatch, setup_test): with freeze_time(parse("2000-01-01 06:00:00")) as fdt: global FDT FDT = fdt monkeypatch.setattr(time, 'sleep', sleepless) c = Camera(sw_cam=True) c.mode_button.value = AUTO c.mode_button.button_path = Path("./camera-switch") c.file_by_date = False #c._camera = FakePiCamera() c._interval = timedelta(minutes=60) c.active_timer = Timed(datetime.time(12), datetime.time(18)) run_until(c, fdt, today_at(23)) images = glob(os.path.join(c.tmv_root, "2000-01-01T*")) assert len(images) == 18 - 12 + 1 # +1 for a fencepost
def check_test_fake2(monkeypatch, setup_test): s = 3 c = Camera(sw_cam=True) c.tmv_root = "./test_fake2/" c.file_by_date = False c.interval = timedelta(seconds=1) c.active_timer = ActiveTimes.factory(dt.now().astimezone().time( ), (dt.now() + timedelta(seconds=s)).astimezone().time(), c) c.camera_inactive_action = CameraInactiveAction.EXCEPTION with pytest.raises(PowerOff): c.run() assert len(c.recent_images) == s + 1 # fencepost images = glob(os.path.join(c.tmv_root, "*.jpg")) assert len(images) == s + 1 # fencepost
def test_overlays(monkeypatch, setup_test): cf = """ [camera] overlays = [ "spinny", "image_name","simple_settings", "bottom_band"] """ with freeze_time(parse("2000-01-01 12:00:00")) as fdt: global FDT FDT = fdt monkeypatch.setattr(time, 'sleep', sleepless) c = Camera(sw_cam=True) #c._camera.width = 1200 #c._camera.height = 900 c.configs(cf) c.file_by_date = False run_until(c, fdt, today_at(13))
def test_camera_inactive_action_2(monkeypatch, setup_test): with freeze_time(parse("2000-01-01 12:00:00")) as fdt: global FDT FDT = fdt monkeypatch.setattr(time, 'sleep', sleepless) c = Camera(sw_cam=True) c.save_images = False c.configs(""" [camera] interval = 900 # 15 minutes on = 'dim' off = 'dark' camera_inactive_action = 'EXCEPTION' """) # with pytest.raises(PowerOff): run_until(c, fdt, today_at(14)) assert c.light_sensor.level == LightLevel.LIGHT assert c.active_timer.active() assert c.active_timer.camera_active()
def test_video(monkeypatch, setup_test): c = Camera(sw_cam=True) c.file_by_date = False with freeze_time(parse("2000-01-01 12:00:00")) as fdt: global FDT FDT = fdt real_sleep = time.sleep monkeypatch.setattr(time, 'sleep', sleepless) # start normally c.mode_button.value = ON c._interval = timedelta(seconds=60) while dt.now() < today_at(13): c.run(1) fdt.tick(timedelta(seconds=1)) # switch to video mode c.mode_button.value = VIDEO vtd = threading.Thread(target=video_server, args=(c, fdt), daemon=True) vtd.start() real_sleep(3) c.mode_button.value = OFF vtd.join() real_sleep(1) # switch to video mode agina : ok c.mode_button.value = VIDEO vtd = threading.Thread(target=video_server, args=(c, fdt), daemon=True) vtd.start() real_sleep(3) c.mode_button.value = OFF vtd.join()
def test_SunCalc(monkeypatch, setup_test): # dawn: datetime.time(4, 28, 38, 892410) # sunrise:datetime.time(4, 55, 38, 480930) # noon: datetime.time(11, 50, 59) # sunset datetime.time(18, 46, 18, 926896) # dusk datetime.time(19, 13, 17, 159158) with freeze_time(parse("2000-01-01 00:00:00")) as fdt: global FDT FDT = fdt monkeypatch.setattr(time, 'sleep', sleepless) c = Camera(sw_cam=True) c.save_images = False c.configs(""" [camera] city = 'Brisbane' interval = 600 on = 'dawn' off = 'sunset' # (2000, 1, 1, 18, 46, 18, 926896, tzinfo=tzlocal()) camera_inactive_action = 'WAIT' """) c._camera = FakePiCamera() assert c.active_timer.active() is False run_until(c, fdt, today_at(4, 30)) assert c.active_timer.active() is True run_until(c, fdt, today_at(12, 30)) assert c.active_timer.active() is True run_until(c, fdt, today_at(18, 30)) assert c.active_timer.active() is True run_until(c, fdt, today_at(18, 40)) run_until(c, fdt, today_at(18, 50)) assert c.active_timer.active() is False run_until(c, fdt, tomorrow_at(8)) assert c.active_timer.active() is True
def test_image_verify(setup_test, caplog): c = Camera(sw_cam=True) stream = BytesIO() # "Rewind" the stream to the beginning so we can read its content stream.seek(0) f = FakePiCamera() f.capture(stream) stream.seek(0) image = Image.open(stream) image.save("should-not-be-required.jpg") fn = Path("test_image_verify.jpg") c.save_image(image, fn) assert Path(fn).is_file() c = Camera(sw_cam=True) image = Image.Image() fn = Path("test_image_dud.jpg") caplog.clear() c.save_image(image, fn) assert not Path(fn).is_file() assert "Image has zero width or height" in caplog.text
def test_image_stats(): # pixel_avg looks # 2020-04-05T14-31-20.jpg .29 light 0 # 2020-04-05T15-24-20.jpg .13 light 1 # 2020-04-05T16-24-20.jpg .08 dim 2 # 2020-04-05T17-24-20.jpg .04 dim 3 # 2020-04-05T18-24-20.jpg .01 dim 4 # thresholds: light > 0.10 # dark < 0.01 with freeze_time(dateutil.parser.parse("2020-04-05T20:00:00")) as fdt: image_files = [] rex = re.compile("^2020-04-05T.*") for r, ds, fs in os.walk(TEST_DATA/"camera_images"): print(ds) image_files = [os.path.join(r, f) for f in fs if rex.match(f) is not None] break # no deeper assert len(image_files) == 5 cam = Camera(sw_cam=True) # usually max_age is 1 hour: use long to make testing easier cam.light_sensor.max_age = timedelta(days=1) for f in sorted(image_files): cam.light_sensor.add_reading( tmv.util.str2dt(f), calc_pixel_average(f)) # pylint: disable=protected-access,pointless-statement assert cam.light_sensor.level == tmv.camera.LightLevel.LIGHT assert len(cam.light_sensor._levels) == 5 cam.light_sensor.max_age = timedelta(hours=4) cam.light_sensor.level assert len(cam.light_sensor._levels) == 3 fdt.move_to(dateutil.parser.parse("2020-04-07T20:00:00")) cam.light_sensor.level assert len(cam.light_sensor._levels) == 0
def video_server(c: Camera, fdt): while c.mode_button.value != VIDEO: c.run(1)