Example #1
0
    def test_is_opening_closing(self):
        """Test reports is_opening and is_closing."""
        travelcalculator = TravelCalculator(25, 50)
        with patch("time.time") as mock_time:
            mock_time.return_value = 1580000000.0
            assert not travelcalculator.is_opening()
            assert not travelcalculator.is_closing()

            travelcalculator.set_position(80)
            assert not travelcalculator.is_opening()
            assert not travelcalculator.is_closing()

            mock_time.return_value = 1580000000.0
            travelcalculator.start_travel_down()
            assert not travelcalculator.is_opening()
            assert travelcalculator.is_closing()

            mock_time.return_value = 1580000004.0
            assert not travelcalculator.is_opening()
            assert travelcalculator.is_closing()

            mock_time.return_value = 1580000005.0
            assert not travelcalculator.is_opening()
            assert not travelcalculator.is_closing()
            # up direction
            travelcalculator.start_travel(50)
            assert travelcalculator.is_opening()
            assert not travelcalculator.is_closing()

            mock_time.return_value = 1580000030.0
            assert not travelcalculator.is_opening()
            assert not travelcalculator.is_closing()
    def test_is_opening_closing(self):
        """Test reports is_opening and is_closing."""
        travelcalculator = TravelCalculator(25, 50)
        with patch('time.time') as mock_time:
            mock_time.return_value = 1580000000.0
            self.assertFalse(travelcalculator.is_opening())
            self.assertFalse(travelcalculator.is_closing())

            travelcalculator.set_position(80)
            self.assertFalse(travelcalculator.is_opening())
            self.assertFalse(travelcalculator.is_closing())

            mock_time.return_value = 1580000000.0
            travelcalculator.start_travel_down()
            self.assertFalse(travelcalculator.is_opening())
            self.assertTrue(travelcalculator.is_closing())

            mock_time.return_value = 1580000004.0
            self.assertFalse(travelcalculator.is_opening())
            self.assertTrue(travelcalculator.is_closing())

            mock_time.return_value = 1580000005.0
            self.assertFalse(travelcalculator.is_opening())
            self.assertFalse(travelcalculator.is_closing())
            # up direction
            travelcalculator.start_travel(50)
            self.assertTrue(travelcalculator.is_opening())
            self.assertFalse(travelcalculator.is_closing())

            mock_time.return_value = 1580000030.0
            self.assertFalse(travelcalculator.is_opening())
            self.assertFalse(travelcalculator.is_closing())
Example #3
0
 def test_init(self):
     """Test initial status."""
     travelcalculator = TravelCalculator(25, 50)
     assert not travelcalculator.is_closed()
     assert not travelcalculator.is_closing()
     assert not travelcalculator.is_opening()
     assert not travelcalculator.is_traveling()
     assert travelcalculator.position_reached()
     assert travelcalculator.current_position() is None
 def test_init(self):
     """Test initial status."""
     travelcalculator = TravelCalculator(25, 50)
     self.assertFalse(travelcalculator.is_closed())
     self.assertFalse(travelcalculator.is_closing())
     self.assertFalse(travelcalculator.is_opening())
     self.assertFalse(travelcalculator.is_traveling())
     self.assertTrue(travelcalculator.position_reached())
     self.assertIsNone(travelcalculator.current_position())
Example #5
0
class RTSRflinkCover(RflinkCommand, CoverEntity, RestoreEntity):
    """RFLink entity which can switch on/stop/off (eg: cover)."""
    def __init__(self, entity_id, rts_my_position, travel_time_down,
                 travel_time_up, **device_config):
        """Initialize the cover."""
        from xknx.devices import TravelCalculator
        self._rts_my_position = rts_my_position
        self._travel_time_down = travel_time_down
        self._travel_time_up = travel_time_up
        self._require_stop_cover = False

        #        self.async_register_callbacks()

        self._unsubscribe_auto_updater = None

        super().__init__(entity_id, None, **device_config)

        self.tc = TravelCalculator(self._travel_time_down,
                                   self._travel_time_up)

    async def async_added_to_hass(self):
        await super().async_added_to_hass()
        """ Only cover's position matters.             """
        """ The rest is calculated from this attribute."""
        old_state = await self.async_get_last_state()
        _LOGGER.debug('async_added_to_hass :: oldState %s', old_state)
        if (old_state is not None and self.tc is not None and
                old_state.attributes.get(ATTR_CURRENT_POSITION) is not None):
            self.tc.set_position(
                self.shift_position(
                    int(old_state.attributes.get(ATTR_CURRENT_POSITION))))

    def _handle_event(self, event):
        """Adjust state if RFLink picks up a remote command for this device."""
        self.cancel_queued_send_commands()
        _LOGGER.debug('_handle_event %s', event)

        # this must be wrong. ON command closes cover
        # command = event['command']
        command = event.get(EVENT_KEY_COMMAND)
        if command in ['on', 'allon', 'up']:
            self._require_stop_cover = False
            self.tc.start_travel_up()
            self.start_auto_updater()
        elif command in ['off', 'alloff', 'down']:
            self._require_stop_cover = False
            self.tc.start_travel_down()
            self.start_auto_updater()
        elif command in ['stop']:
            self._handle_my_button()

    def _handle_my_button(self):
        """Handle the MY button press"""
        self._require_stop_cover = False
        if self.tc.is_traveling():
            _LOGGER.debug('_handle_my_button :: button stops cover')
            self.tc.stop()
            self.stop_auto_updater()
        elif self._rts_my_position is not None:
            _LOGGER.debug('_handle_my_button :: button sends to MY')
            self.tc.start_travel(self.shift_position(self._rts_my_position))
            self.start_auto_updater()

    @property
    def device_state_attributes(self):
        """Return the device state attributes."""
        attr = {}
        super_attr = super().device_state_attributes
        if super_attr is not None:
            attr.update(super_attr)
        if self._rts_my_position is not None:
            attr[CONF_MY_POSITION] = self._rts_my_position
        if self._travel_time_down is not None:
            attr[CONF_TRAVELLING_TIME_DOWN] = self._travel_time_down
        if self._travel_time_up is not None:
            attr[CONF_TRAVELLING_TIME_UP] = self._travel_time_up
        return attr

    @property
    def current_cover_position(self):
        """Return the current position of the cover."""
        return self.shift_position(self.tc.current_position())

    @property
    def is_opening(self):
        """Return if the cover is opening or not."""
        return self.tc.is_opening()

    @property
    def is_closing(self):
        """Return if the cover is closing or not."""
        return self.tc.is_closing()

    @property
    def is_closed(self):
        """Return if the cover is closed."""
        return self.tc.is_closed()

    @property
    def assumed_state(self):
        """Return True because covers can be stopped midway."""
        return True

    async def async_set_cover_position(self, **kwargs):
        """Move the cover to a specific position."""
        if ATTR_POSITION in kwargs:
            position = kwargs[ATTR_POSITION]
            _LOGGER.debug('async_set_cover_position: %d', position)
            await self.set_position(position)

    async def async_close_cover(self, **kwargs):
        """Turn the device close."""
        _LOGGER.debug('async_close_cover')
        self.tc.start_travel_down()
        self._require_stop_cover = False
        self.start_auto_updater()
        await self._async_handle_command(SERVICE_CLOSE_COVER)

    async def async_open_cover(self, **kwargs):
        """Turn the device open."""
        _LOGGER.debug('async_open_cover')
        self.tc.start_travel_up()
        self._require_stop_cover = False
        self.start_auto_updater()
        await self._async_handle_command(SERVICE_OPEN_COVER)

    async def async_stop_cover(self, **kwargs):
        """Turn the device stop."""
        _LOGGER.debug('async_stop_cover')
        self._handle_my_button()
        await self._async_handle_command(SERVICE_STOP_COVER)

    async def set_position(self, position):
        _LOGGER.debug('set_position')
        """Move cover to a designated position."""
        current_position = self.shift_position(self.tc.current_position())
        _LOGGER.debug('set_position :: current_position: %d, new_position: %d',
                      current_position, position)
        command = None
        if position < current_position:
            command = SERVICE_CLOSE_COVER
        elif position > current_position:
            command = SERVICE_OPEN_COVER
        if command is not None:
            self._require_stop_cover = True
            self.start_auto_updater()
            self.tc.start_travel(self.shift_position(position))
            _LOGGER.debug('set_position :: command %s', command)
            await self._async_handle_command(command)
        return

    def start_auto_updater(self):
        """Start the autoupdater to update HASS while cover is moving."""
        _LOGGER.debug('start_auto_updater')
        if self._unsubscribe_auto_updater is None:
            _LOGGER.debug('init _unsubscribe_auto_updater')
            #            self._unsubscribe_auto_updater = async_track_utc_time_change(self.hass, self.auto_updater_hook)
            interval = timedelta(seconds=0.1)
            self._unsubscribe_auto_updater = async_track_time_interval(
                self.hass, self.auto_updater_hook, interval)

    @callback
    def auto_updater_hook(self, now):
        """Call for the autoupdater."""
        _LOGGER.debug('auto_updater_hook')
        self.async_write_ha_state()
        if self.position_reached():
            _LOGGER.debug('auto_updater_hook :: position_reached')
            self.stop_auto_updater()
        self.hass.async_create_task(self.auto_stop_if_necessary())

    def stop_auto_updater(self):
        """Stop the autoupdater."""
        _LOGGER.debug('stop_auto_updater')
        if self._unsubscribe_auto_updater is not None:
            self._unsubscribe_auto_updater()
            self._unsubscribe_auto_updater = None

    def position_reached(self):
        """Return if cover has reached its final position."""
        return self.tc.position_reached()

    async def auto_stop_if_necessary(self):
        """Do auto stop if necessary."""
        # If device does not support auto_positioning,
        # we have to stop the device when position is reached.
        # unless device was traveling to fully open
        # or fully closed state
        if self.position_reached():
            if (self._require_stop_cover and not self.tc.is_closed()
                    and not self.tc.is_open()):
                _LOGGER.debug('auto_stop_if_necessary :: calling stop command')
                await self._async_handle_command(SERVICE_STOP_COVER)
            self.tc.stop()

    def shift_position(self, position):
        """Calculate 100 complement position"""
        try:
            return 100 - position
        except TypeError:
            return None