def test_inactive_when_no_ess(self): # Determine seconds since midnight on timer right now. now = timer_manager.datetime midnight = datetime.combine(now.date(), time.min) stamp = (now - midnight).seconds # Set a schedule to start in 1 minutes and stop in another 1. self._set_setting('/Settings/CGwacs/BatteryLife/State', 4) self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Day', 7) self._set_setting( '/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Start', stamp + 60) self._set_setting( '/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Duration', 60) self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Soc', 100) # No ESS installed self._monitor.set_value(self.vebus, '/Hub4/AssistantId', None) # Travel 1 minute ahead, Charging should remain inactive because no ESS timer_manager.run(66000) self._check_external_values( {'com.victronenergy.hub4': { '/Overrides/ForceCharge': 0, }})
def test_scheduled_for_tomorrow(self): # Determine seconds since midnight on timer right now. now = timer_manager.datetime midnight = datetime.combine(now.date(), time.min) stamp = (now - midnight).seconds today = (now.date().weekday() + 1) % 7 tomorrow = (today + 1) % 7 # Set a schedule to start in 2 minutes and stop in another 10. self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Day', today) self._set_setting( '/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Start', stamp + 60) self._set_setting( '/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Duration', 600) self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Soc', 100) # Travel 1 minute ahead timer_manager.run(65000) self._check_external_values( {'com.victronenergy.hub4': { '/Overrides/ForceCharge': 1, }}) # But if it was set for tomorrow it wouldn't match self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Day', tomorrow) timer_manager.run(5000) self._check_external_values( {'com.victronenergy.hub4': { '/Overrides/ForceCharge': 0, }})
def test_run_from_yesterday(self): # Determine seconds since midnight on timer right now. now = timer_manager.datetime midnight = datetime.combine(now.date(), time.min) stamp = (now - midnight).seconds yesterday = now.date().weekday() # Set a schedule that started a minute before midnight yesterday # and will expire a minute from now. self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Day', yesterday) self._set_setting( '/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Start', 86340) self._set_setting( '/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Duration', stamp + 120) self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Soc', 100) timer_manager.run(5000) self._check_external_values( {'com.victronenergy.hub4': { '/Overrides/ForceCharge': 1, }}) timer_manager.run(60000) self._check_external_values( {'com.victronenergy.hub4': { '/Overrides/ForceCharge': 0, }})
def test_run_from_yesterday(self): # Determine seconds since midnight on timer right now. now = timer_manager.datetime midnight = datetime.combine(now.date(), time.min) stamp = (now-midnight).seconds yesterday = now.date().weekday() # Set a schedule that started a minute before midnight yesterday # and will expire a minute from now. self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Day', yesterday) self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Start', 86340) self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Duration', stamp + 120) self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Soc', 100) timer_manager.run(5000) self._check_external_values({ 'com.victronenergy.hub4': { '/Overrides/ForceCharge': 1, }}) timer_manager.run(60000) self._check_external_values({ 'com.victronenergy.hub4': { '/Overrides/ForceCharge': 0, }})
def test_scheduled_for_tomorrow(self): # Determine seconds since midnight on timer right now. now = timer_manager.datetime midnight = datetime.combine(now.date(), time.min) stamp = (now-midnight).seconds today = (now.date().weekday() + 1) % 7 tomorrow = (today + 1) % 7 # Set a schedule to start in 2 minutes and stop in another 10. self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Day', today) self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Start', stamp+60) self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Duration', 600) self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Soc', 100) # Travel 1 minute ahead timer_manager.run(65000) self._check_external_values({ 'com.victronenergy.hub4': { '/Overrides/ForceCharge': 1, }}) # But if it was set for tomorrow it wouldn't match self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Day', tomorrow) timer_manager.run(5000) self._check_external_values({ 'com.victronenergy.hub4': { '/Overrides/ForceCharge': 0, }})
def test_flag_reset(self): self._set_setting('/Settings/CGwacs/BatteryLife/Flags', Flags.Discharged | Flags.Float | Flags.Absorption) self._update_values() self._check_settings( {'flags': Flags.Discharged | Flags.Float | Flags.Absorption}) # It was day and it was night, the second day. timer_manager.run(86400000) self._check_settings({ 'flags': 0, })
def test_flag_reset(self): self._set_setting('/Settings/CGwacs/BatteryLife/Flags', Flags.Discharged | Flags.Float | Flags.Absorption) self._update_values() self._check_settings({ 'flags': Flags.Discharged | Flags.Float | Flags.Absorption }) # It was day and it was night, the second day. timer_manager.run(86400000) self._check_settings({ 'flags': 0, })
def test_slow_charge(self): self._set_setting('/Settings/CGwacs/BatteryLife/SocLimit', 55) self._set_setting('/Settings/CGwacs/BatteryLife/State', State.BLSustain) # Sustain self._set_setting('/Settings/CGwacs/BatteryLife/Flags', Flags.Discharged) # Discharged self._set_setting('/Settings/CGwacs/BatteryLife/DischargedTime', 1) timer_manager.run(900000) self._check_settings({ 'state': State.BLForceCharge, # Slow charge 'flags': Flags.Discharged, }) self._monitor.set_value(self.vebus, '/Soc', 60.01) self._update_values() self._check_settings({ 'state': State.BLDischarged, # Back into Discharged state 'flags': Flags.Discharged, })
def test_inactive_when_keepcharged(self): # Determine seconds since midnight on timer right now. now = timer_manager.datetime midnight = datetime.combine(now.date(), time.min) stamp = (now-midnight).seconds # Set a schedule to start in 1 minutes and stop in another 1. self._set_setting('/Settings/CGwacs/BatteryLife/State', 9) self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Day', 7) self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Start', stamp+60) self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Duration', 60) self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Soc', 100) # Travel 1 minute ahead, but it should remain out of charge mode # because we're in KeepBatteriesCharged. timer_manager.run(66000) self._check_external_values({ 'com.victronenergy.hub4': { '/Overrides/ForceCharge': 0, }})
def test_scheduled_charge_multiple_windows(self): # Determine seconds since midnight on timer right now. now = timer_manager.datetime midnight = datetime.combine(now.date(), time.min) stamp = (now - midnight).seconds # Set a schedule to start in 1 minutes and stop in 2, then another # to start at 3 and stop at 4. self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Day', 7) self._set_setting( '/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Start', stamp + 60) self._set_setting( '/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Duration', 60) self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Soc', 100) self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/1/Day', 7) self._set_setting( '/Settings/CGwacs/BatteryLife/Schedule/Charge/1/Start', stamp + 180) self._set_setting( '/Settings/CGwacs/BatteryLife/Schedule/Charge/1/Duration', 60) self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/1/Soc', 100) # Another minute or so, it should pop unto scheduled charge timer_manager.run(65000) self._check_external_values( {'com.victronenergy.hub4': { '/Overrides/ForceCharge': 1, }}) timer_manager.run(65000) self._check_external_values( {'com.victronenergy.hub4': { '/Overrides/ForceCharge': 0, }}) timer_manager.run(65000) self._check_external_values( {'com.victronenergy.hub4': { '/Overrides/ForceCharge': 1, }}) timer_manager.run(65000) self._check_external_values( {'com.victronenergy.hub4': { '/Overrides/ForceCharge': 0, }})
def test_inactive_when_no_ess(self): # Determine seconds since midnight on timer right now. now = timer_manager.datetime midnight = datetime.combine(now.date(), time.min) stamp = (now-midnight).seconds # Set a schedule to start in 1 minutes and stop in another 1. self._set_setting('/Settings/CGwacs/BatteryLife/State', 4) self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Day', 7) self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Start', stamp+60) self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Duration', 60) self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Soc', 100) # No ESS installed self._monitor.set_value(self.vebus, '/Hub4/AssistantId', None) # Travel 1 minute ahead, Charging should remain inactive because no ESS timer_manager.run(66000) self._check_external_values({ 'com.victronenergy.hub4': { '/Overrides/ForceCharge': 0, }})
def test_scheduled_charge(self): # Determine seconds since midnight on timer right now. now = timer_manager.datetime midnight = datetime.combine(now.date(), time.min) stamp = (now - midnight).seconds # Set a schedule to start in 2 minutes and stop in another 1. self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Day', 7) self._set_setting( '/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Start', stamp + 120) self._set_setting( '/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Duration', 60) self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Soc', 100) # Travel 1 minute ahead, state should remain unchanged. timer_manager.run(60000) self._check_external_values( {'com.victronenergy.hub4': { '/Overrides/ForceCharge': 0, }}) self._check_values({'/Control/ScheduledCharge': 0}) # Another minute or so, it should pop unto scheduled charge timer_manager.run(66000) self._check_external_values( {'com.victronenergy.hub4': { '/Overrides/ForceCharge': 1, }}) # SystemState should indicate what happened. state only updates # when something changes, and our async update fools the unit tests, # so fake a change by moving the SoC. self._monitor.set_value(self.vebus, '/Soc', 70) timer_manager.run(1000) self._check_values({ '/SystemState/State': 0x103, '/Control/ScheduledCharge': 1 }) # Another minute and scheduled charging will end. timer_manager.run(65000) self._check_external_values( {'com.victronenergy.hub4': { '/Overrides/ForceCharge': 0, }})
def test_scheduled_charge(self): # Determine seconds since midnight on timer right now. now = timer_manager.datetime midnight = datetime.combine(now.date(), time.min) stamp = (now - midnight).seconds # Set a schedule to start in 2 minutes and stop in another 1. self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Day', 7) self._set_setting( '/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Start', stamp + 120) self._set_setting( '/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Duration', 60) self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Soc', 100) # Travel 1 minute ahead, state should remain unchanged. timer_manager.run(60000) self._check_external_values( {'com.victronenergy.hub4': { '/Overrides/ForceCharge': 0, }}) self._check_values({'/Control/ScheduledCharge': 0}) # Another minute or so, it should pop unto scheduled charge timer_manager.run(66000) self._check_external_values( {'com.victronenergy.hub4': { '/Overrides/ForceCharge': 1, }}) # SystemState should indicate what happened self._check_values({ '/SystemState/State': 0x103, '/Control/ScheduledCharge': 1 }) # Another minute or so, increase Soc as well, it should pop out again timer_manager.run(33000) self._monitor.set_value(self.vebus, '/Soc', 70) timer_manager.run(33000) self._check_external_values( {'com.victronenergy.hub4': { '/Overrides/ForceCharge': 0, }})
def test_inactive_when_keepcharged(self): # Determine seconds since midnight on timer right now. now = timer_manager.datetime midnight = datetime.combine(now.date(), time.min) stamp = (now - midnight).seconds # Set a schedule to start in 1 minutes and stop in another 1. self._set_setting('/Settings/CGwacs/BatteryLife/State', 9) self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Day', 7) self._set_setting( '/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Start', stamp + 60) self._set_setting( '/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Duration', 60) self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Soc', 100) # Travel 1 minute ahead, but it should remain out of charge mode # because we're in KeepBatteriesCharged. timer_manager.run(66000) self._check_external_values( {'com.victronenergy.hub4': { '/Overrides/ForceCharge': 0, }})
def test_scheduled_charge_multiple_windows(self): # Determine seconds since midnight on timer right now. now = timer_manager.datetime midnight = datetime.combine(now.date(), time.min) stamp = (now-midnight).seconds # Set a schedule to start in 1 minutes and stop in 2, then another # to start at 3 and stop at 4. self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Day', 7) self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Start', stamp+60) self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Duration', 60) self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Soc', 100) self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/1/Day', 7) self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/1/Start', stamp+180) self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/1/Duration', 60) self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/1/Soc', 100) # Another minute or so, it should pop unto scheduled charge timer_manager.run(65000) self._check_external_values({ 'com.victronenergy.hub4': { '/Overrides/ForceCharge': 1, }}) timer_manager.run(65000) self._check_external_values({ 'com.victronenergy.hub4': { '/Overrides/ForceCharge': 0, }}) timer_manager.run(65000) self._check_external_values({ 'com.victronenergy.hub4': { '/Overrides/ForceCharge': 1, }}) timer_manager.run(65000) self._check_external_values({ 'com.victronenergy.hub4': { '/Overrides/ForceCharge': 0, }})
def test_scheduled_charge(self): # Determine seconds since midnight on timer right now. now = timer_manager.datetime midnight = datetime.combine(now.date(), time.min) stamp = (now-midnight).seconds # Set a schedule to start in 2 minutes and stop in another 1. self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Day', 7) self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Start', stamp+120) self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Duration', 60) self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Soc', 100) # Travel 1 minute ahead, state should remain unchanged. timer_manager.run(60000) self._check_external_values({ 'com.victronenergy.hub4': { '/Overrides/ForceCharge': 0, }}) self._check_values({'/Control/ScheduledCharge': 0}) # Another minute or so, it should pop unto scheduled charge timer_manager.run(66000) self._check_external_values({ 'com.victronenergy.hub4': { '/Overrides/ForceCharge': 1, }}) # SystemState should indicate what happened self._check_values({ '/SystemState/State': 0x103, '/Control/ScheduledCharge': 1}) # Another minute or so, increase Soc as well, it should pop out again timer_manager.run(33000) self._monitor.set_value(self.vebus, '/Soc', 70) timer_manager.run(33000) self._check_external_values({ 'com.victronenergy.hub4': { '/Overrides/ForceCharge': 0, }})
def test_scheduled_charge_stop_on_soc(self): # Add solar charger self._add_device('com.victronenergy.solarcharger.ttyO1', { '/State': 252, '/Link/NetworkMode': 5, '/Link/ChargeVoltage': 26, '/Link/VoltageSense': None, '/Dc/0/Voltage': 24, '/Dc/0/Current': 10, '/FirmwareVersion': 0x129 }, connection='VE.Direct') # Determine seconds since midnight on timer right now. now = timer_manager.datetime midnight = datetime.combine(now.date(), time.min) stamp = (now - midnight).seconds # Set a schedule to start in 2 minutes and stop in 4. self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Day', 7) self._set_setting( '/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Start', stamp + 120) self._set_setting( '/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Duration', 180) self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Soc', 70) # Travel 1 minute ahead, state should remain unchanged. timer_manager.run(60000) self._check_external_values( {'com.victronenergy.hub4': { '/Overrides/ForceCharge': 0, }}) # Another minute or so, it should pop into scheduled charge timer_manager.run(66000) self._check_external_values( {'com.victronenergy.hub4': { '/Overrides/ForceCharge': 1, }}) # Another minute or so, Soc increases but not enough timer_manager.run(33000) self._monitor.set_value(self.vebus, '/Soc', 68) timer_manager.run(33000) self._check_external_values( {'com.victronenergy.hub4': { '/Overrides/ForceCharge': 1, }}) # Another minute or so, Soc increases to right level. Discharge # is disabled while we are inside the window self._monitor.set_value(self.vebus, '/Soc', 70) timer_manager.run(66000) self._check_external_values({ 'com.victronenergy.hub4': { '/Overrides/ForceCharge': 0, '/Overrides/MaxDischargePower': 192, # 80% of available PV } }) # When we emerge from the charge window, discharge is allowed again. timer_manager.run(66000) self._check_external_values({ 'com.victronenergy.hub4': { '/Overrides/ForceCharge': 0, '/Overrides/MaxDischargePower': -1, } })
def test_hysteresis(self): """ Test that battery is allowed to drop 5% before re-acivating recharge, to avoid pulse-charging in a large window if target SOC is reached early. """ # Determine seconds since midnight on timer right now. now = timer_manager.datetime midnight = datetime.combine(now.date(), time.min) stamp = (now - midnight).seconds # Set a schedule to start now and stop in 5 minutes self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Day', 7) self._set_setting( '/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Start', stamp) self._set_setting( '/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Duration', 300) self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Soc', 70) # Travel just far enough ahead to trigger the 5-second task in the delegate timer_manager.run(5000) self._check_external_values( {'com.victronenergy.hub4': { '/Overrides/ForceCharge': 1, }}) # Increase the SOC to match the target, check that charging stopped. self._monitor.set_value(self.vebus, '/Soc', 70) timer_manager.run(5000) self._check_external_values( {'com.victronenergy.hub4': { '/Overrides/ForceCharge': 0, }}) # Reduce the SOC a little and check that hysteresis is applied self._monitor.set_value(self.vebus, '/Soc', 65) timer_manager.run(5000) self._check_external_values( {'com.victronenergy.hub4': { '/Overrides/ForceCharge': 0, }}) # Reduce SOC below the lower limit and check that charging reactivates self._monitor.set_value(self.vebus, '/Soc', 64.9) timer_manager.run(5000) self._check_external_values( {'com.victronenergy.hub4': { '/Overrides/ForceCharge': 1, }}) # Check again that it stops once the target is reached. self._monitor.set_value(self.vebus, '/Soc', 69.9) timer_manager.run(5000) self._check_external_values( {'com.victronenergy.hub4': { '/Overrides/ForceCharge': 1, }}) self._monitor.set_value(self.vebus, '/Soc', 70) timer_manager.run(5000) self._check_external_values( {'com.victronenergy.hub4': { '/Overrides/ForceCharge': 0, }})
def test_scheduled_charge_stop_on_soc(self): # Add solar charger self._add_device('com.victronenergy.solarcharger.ttyO1', { '/State': 252, '/Link/NetworkMode': 5, '/Link/ChargeVoltage': 26, '/Link/VoltageSense': None, '/Dc/0/Voltage': 24, '/Dc/0/Current': 10, '/FirmwareVersion': 0x129}, connection='VE.Direct') # Determine seconds since midnight on timer right now. now = timer_manager.datetime midnight = datetime.combine(now.date(), time.min) stamp = (now-midnight).seconds # Set a schedule to start in 2 minutes and stop in 4. self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Day', 7) self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Start', stamp+120) self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Duration', 180) self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Soc', 70) # Travel 1 minute ahead, state should remain unchanged. timer_manager.run(60000) self._check_external_values({ 'com.victronenergy.hub4': { '/Overrides/ForceCharge': 0, }}) # Another minute or so, it should pop into scheduled charge timer_manager.run(66000) self._check_external_values({ 'com.victronenergy.hub4': { '/Overrides/ForceCharge': 1, }}) # Another minute or so, Soc increases but not enough timer_manager.run(33000) self._monitor.set_value(self.vebus, '/Soc', 68) timer_manager.run(33000) self._check_external_values({ 'com.victronenergy.hub4': { '/Overrides/ForceCharge': 1, }}) # Another minute or so, Soc increases to right level. Discharge # is disabled while we are inside the window self._monitor.set_value(self.vebus, '/Soc', 70) timer_manager.run(66000) self._check_external_values({ 'com.victronenergy.hub4': { '/Overrides/ForceCharge': 0, '/Overrides/MaxDischargePower': 192, # 80% of available PV }}) # When we emerge from the charge window, discharge is allowed again. timer_manager.run(66000) self._check_external_values({ 'com.victronenergy.hub4': { '/Overrides/ForceCharge': 0, '/Overrides/MaxDischargePower': -1, }})
def test_scheduled_charge_stop_on_soc(self): # Determine seconds since midnight on timer right now. now = timer_manager.datetime midnight = datetime.combine(now.date(), time.min) stamp = (now - midnight).seconds # Set a schedule to start in 2 minutes and stop in 4. self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Day', 7) self._set_setting( '/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Start', stamp + 120) self._set_setting( '/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Duration', 180) self._set_setting('/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Soc', 70) # Travel 1 minute ahead, state should remain unchanged. timer_manager.run(60000) self._check_external_values( {'com.victronenergy.hub4': { '/Overrides/ForceCharge': 0, }}) # Another minute or so, it should pop into scheduled charge timer_manager.run(66000) self._check_external_values( {'com.victronenergy.hub4': { '/Overrides/ForceCharge': 1, }}) # Another minute or so, Soc increases but not enough timer_manager.run(33000) self._monitor.set_value(self.vebus, '/Soc', 68) timer_manager.run(33000) self._check_external_values( {'com.victronenergy.hub4': { '/Overrides/ForceCharge': 1, }}) # Another minute or so, Soc increases to right level. Discharge # is disabled while we are inside the window self._monitor.set_value(self.vebus, '/Soc', 70) timer_manager.run(66000) self._check_external_values({ 'com.victronenergy.hub4': { '/Overrides/ForceCharge': 0, '/Overrides/MaxDischargePower': 1, } }) # When we emerge from the charge window, discharge is allowed again. timer_manager.run(66000) self._check_external_values({ 'com.victronenergy.hub4': { '/Overrides/ForceCharge': 0, '/Overrides/MaxDischargePower': -1, } })