コード例 #1
0
ファイル: __init__.py プロジェクト: nielstron/home-assistant
def calculate_offset(event, offset):
    """Calculate event offset.

    Return the updated event with the offset_time included.
    """
    summary = event.get('summary', '')
    # check if we have an offset tag in the message
    # time is HH:MM or MM
    reg = '{}([+-]?[0-9]{{0,2}}(:[0-9]{{0,2}})?)'.format(offset)
    search = re.search(reg, summary)
    if search and search.group(1):
        time = search.group(1)
        if ':' not in time:
            if time[0] == '+' or time[0] == '-':
                time = '{}0:{}'.format(time[0], time[1:])
            else:
                time = '0:{}'.format(time)

        offset_time = time_period_str(time)
        summary = (summary[:search.start()] + summary[search.end():]).strip()
        event['summary'] = summary
    else:
        offset_time = dt.dt.timedelta()  # default it

    event['offset_time'] = offset_time
    return event
コード例 #2
0
ファイル: config_flow.py プロジェクト: siku2/hass-weatherlink
    async def async_step_misc(self, user_input=None):
        from . import get_update_interval

        errors = {}
        if user_input is not None:
            self.options[KEY_LISTEN_TO_BROADCASTS] = user_input[
                KEY_LISTEN_TO_BROADCASTS]
            try:
                self.options["update_interval"] = cv.time_period_str(
                    user_input["update_interval"]).total_seconds()
            except vol.Error:
                errors["update_interval"] = "invalid_time_period"
            else:
                return await self.async_step_units()

        return self.async_show_form(
            step_id="misc",
            data_schema=vol.Schema({
                vol.Required(
                    "update_interval",
                    default=str(get_update_interval(self.config_entry)),
                ):
                str,
                vol.Required(
                    KEY_LISTEN_TO_BROADCASTS,
                    default=get_listen_to_broadcasts(self.config_entry),
                ):
                bool,
            }),
            errors=errors,
        )
コード例 #3
0
def parse_timedelta_or_default(input_str: str, default: datetime.timedelta = None) -> datetime.timedelta:
    if not input_str:
        return default
    try:
        return cv.time_period_str(input_str)
    except vol.Invalid:
        return default
コード例 #4
0
async def test_set_auto_off_service_fail(hass, mock_bridge, mock_api, caplog):
    """Test set auto off service failed."""
    await init_integration(hass)
    assert mock_bridge

    device = DUMMY_WATER_HEATER_DEVICE
    entity_id = f"{SWITCH_DOMAIN}.{slugify(device.name)}"

    with patch(
            "homeassistant.components.switcher_kis.switch.SwitcherApi.set_auto_shutdown",
            return_value=None,
    ) as mock_set_auto_shutdown:
        await hass.services.async_call(
            DOMAIN,
            SERVICE_SET_AUTO_OFF_NAME,
            {
                ATTR_ENTITY_ID: entity_id,
                CONF_AUTO_OFF: DUMMY_AUTO_OFF_SET
            },
            blocking=True,
        )

        assert mock_api.call_count == 2
        mock_set_auto_shutdown.assert_called_once_with(
            time_period_str(DUMMY_AUTO_OFF_SET))
        assert (f"Call api for {device.name} failed, api: 'set_auto_shutdown'"
                in caplog.text)
        state = hass.states.get(entity_id)
        assert state.state == STATE_UNAVAILABLE
コード例 #5
0
def calculate_offset(event, offset):
    """Calculate event offset.

    Return the updated event with the offset_time included.
    """
    summary = event.get("summary", "")
    # check if we have an offset tag in the message
    # time is HH:MM or MM
    reg = f"{offset}([+-]?[0-9]{{0,2}}(:[0-9]{{0,2}})?)"
    search = re.search(reg, summary)
    if search and search.group(1):
        time = search.group(1)
        if ":" not in time:
            if time[0] == "+" or time[0] == "-":
                time = f"{time[0]}0:{time[1:]}"
            else:
                time = f"0:{time}"

        offset_time = time_period_str(time)
        summary = (summary[:search.start()] + summary[search.end():]).strip()
        event["summary"] = summary
    else:
        offset_time = dt.dt.timedelta()  # default it

    event["offset_time"] = offset_time
    return event
コード例 #6
0
 def __init__(self, config: Dict):
     """Initialize a timer."""
     self._config: dict = config
     self.editable: bool = True
     self._state: str = STATUS_IDLE
     self._duration = cv.time_period_str(config[CONF_DURATION])
     self._remaining = self._duration
     self._restore = config.get(CONF_RESTORE, DEFAULT_RESTORE)
     if self._restore:
         self._restore_grace_period: Optional[timedelta] \
             = cv.time_period_str(config.get(CONF_RESTORE_GRACE_PERIOD, 
                 DEFAULT_RESTORE_GRACE_PERIOD))
     else:
         self._restore_grace_period: Optional[timedelta] = None
     
     self._end: Optional[datetime] = None
     self._listener = None
コード例 #7
0
    async def async_update_config(self, config: Dict) -> None:
        """Handle when the config is updated."""
        self._config = config
        self._duration = cv.time_period_str(config[CONF_DURATION])
        self._restore = config.get(CONF_RESTORE, DEFAULT_RESTORE)
        if self._restore:
            self._restore_grace_period: Optional[timedelta] \
                = cv.time_period_str(config.get(CONF_RESTORE_GRACE_PERIOD,
                    DEFAULT_RESTORE_GRACE_PERIOD))
            self._restore_state(self._state, self.state_attributes)
        else:
            self._listener = None
            self._state = STATUS_IDLE
            self._end = None
            self._remaining = timedelta()
            self._restore_grace_period = timedelta()

        self.async_write_ha_state()
コード例 #8
0
 def __init__(self, config: dict):
     """Initialize a timer."""
     self._config: dict = config
     self.editable: bool = True
     self._state: str = STATUS_IDLE
     self._duration = cv.time_period_str(config[CONF_DURATION])
     self._remaining: timedelta | None = None
     self._end: datetime | None = None
     self._listener = None
コード例 #9
0
ファイル: __init__.py プロジェクト: zhangziran/common_timer
    def handle_task(self, entity_id, operation, **kwargs):
        """ handle task when time arrive.
            if handler take long time, use hass.async_add_job(func) to exec in another thread. 
        """
        _LOGGER.debug("handle_task(%s): operation = %s.", entity_id, operation)
        task = self._get_task(entity_id)
        task['handle'] = None
        task['remaining'] = '0:00:00'

        if operation == 'temporary_on':
            ratio = self._ratio if task['operation'] == operation else 1
            delay = int(
                time_period_str(task['duration']).total_seconds() * ratio)
            task['handle'] = self._queue.insert(entity_id,
                                                str(timedelta(seconds=delay)),
                                                self.handle_task,
                                                'temporary_off')
            task['next_operation'] = 'off'
            task['exec_time'] = datetime.now(
            ) + self._queue.get_remaining_time(task['handle'])
            operation = 'on'
        elif operation == 'temporary_off':
            ratio = self._ratio if task['operation'] == operation else 1
            delay = int(
                time_period_str(task['duration']).total_seconds() * ratio)
            task['handle'] = self._queue.insert(entity_id,
                                                str(timedelta(seconds=delay)),
                                                self.handle_task,
                                                'temporary_on')
            task['next_operation'] = 'on'
            task['exec_time'] = datetime.now(
            ) + self._queue.get_remaining_time(task['handle'])
            operation = 'off'
        elif operation == 'custom':
            pass
        service = 'turn_' + operation
        state = operation
        self.set_state(entity_id,
                       state=state,
                       service=service,
                       force_update=True)
        _LOGGER.debug("handle_task finish:{}({})".format(service, entity_id))
コード例 #10
0
 async def async_update_config(self, config: Dict) -> None:
     """Handle when the config is updated."""
     self._config = config
     self._duration = cv.time_period_str(config[CONF_DURATION])
     self._restore = config.get(CONF_RESTORE, DEFAULT_RESTORE)
     if self._restore:
         self._restore_grace_period: Optional[timedelta] \
             = config.get(CONF_RESTORE_GRACE_PERIOD, DEFAULT_RESTORE_GRACE_PERIOD)
     else:
         self._restore_grace_period: Optional[timedelta] = None
     self.async_write_ha_state()
コード例 #11
0
async def test_set_auto_off_service(
    hass: HomeAssistantType,
    mock_bridge: Generator[None, Any, None],
    mock_api: Generator[None, Any, None],
    hass_owner_user: MockUser,
) -> None:
    """Test the set_auto_off service."""
    assert await async_setup_component(hass, DOMAIN, MANDATORY_CONFIGURATION)

    await hass.async_block_till_done()

    assert hass.services.has_service(DOMAIN, SERVICE_SET_AUTO_OFF_NAME)

    await hass.services.async_call(
        DOMAIN,
        SERVICE_SET_AUTO_OFF_NAME,
        {
            CONF_ENTITY_ID: SWITCH_ENTITY_ID,
            CONF_AUTO_OFF: DUMMY_AUTO_OFF_SET
        },
        blocking=True,
        context=Context(user_id=hass_owner_user.id),
    )

    with raises(UnknownUser) as unknown_user_exc:
        await hass.services.async_call(
            DOMAIN,
            SERVICE_SET_AUTO_OFF_NAME,
            {
                CONF_ENTITY_ID: SWITCH_ENTITY_ID,
                CONF_AUTO_OFF: DUMMY_AUTO_OFF_SET
            },
            blocking=True,
            context=Context(user_id="not_real_user"),
        )

    assert unknown_user_exc.type is UnknownUser

    with patch(
            "homeassistant.components.switcher_kis.switch.SwitcherV2Api.set_auto_shutdown"
    ) as mock_set_auto_shutdown:
        await hass.services.async_call(
            DOMAIN,
            SERVICE_SET_AUTO_OFF_NAME,
            {
                CONF_ENTITY_ID: SWITCH_ENTITY_ID,
                CONF_AUTO_OFF: DUMMY_AUTO_OFF_SET
            },
        )

        await hass.async_block_till_done()

        mock_set_auto_shutdown.assert_called_once_with(
            time_period_str(DUMMY_AUTO_OFF_SET))
コード例 #12
0
    def __init__(self, config: dict) -> None:
        """Initialize a timer."""
        self._config: dict = config
        self.editable: bool = True
        self._state: str = STATUS_IDLE
        self._duration = cv.time_period_str(config[CONF_DURATION])
        self._remaining: timedelta | None = None
        self._end: datetime | None = None
        self._listener: Callable[[], None] | None = None

        self._attr_should_poll = False
        self._attr_force_update = True
コード例 #13
0
    def update(self):
        """Search for the next event."""
        if not self.data or not self.data.update():
            # update cached, don't do anything
            return

        if not self.data.event:
            # we have no event to work on, make sure we're clean
            self.cleanup()
            return

        def _get_date(date):
            """Get the dateTime from date or dateTime as a local."""
            if 'date' in date:
                return dt.as_utc(
                    dt.dt.datetime.combine(dt.parse_date(date['date']),
                                           dt.dt.time()))
            else:
                return dt.parse_datetime(date['dateTime'])

        start = _get_date(self.data.event['start'])
        end = _get_date(self.data.event['end'])

        summary = self.data.event['summary']

        # check if we have an offset tag in the message
        # time is HH:MM or MM
        reg = '{}([+-]?[0-9]{{0,2}}(:[0-9]{{0,2}})?)'.format(self._offset)
        search = re.search(reg, summary)
        if search and search.group(1):
            time = search.group(1)
            if ':' not in time:
                if time[0] == '+' or time[0] == '-':
                    time = '{}0:{}'.format(time[0], time[1:])
                else:
                    time = '0:{}'.format(time)

            offset_time = time_period_str(time)
            summary = (summary[:search.start()] + summary[search.end():]) \
                .strip()
        else:
            offset_time = dt.dt.timedelta()  # default it

        # cleanup the string so we don't have a bunch of double+ spaces
        self._cal_data['message'] = re.sub('  +', '', summary).strip()

        self._cal_data['offset_time'] = offset_time
        self._cal_data['location'] = self.data.event.get('location', '')
        self._cal_data['description'] = self.data.event.get('description', '')
        self._cal_data['start'] = start
        self._cal_data['end'] = end
        self._cal_data['all_day'] = 'date' in self.data.event['start']
コード例 #14
0
    def update(self):
        """Search for the next event."""
        if not self.data or not self.data.update():
            # update cached, don't do anything
            return

        if not self.data.event:
            # we have no event to work on, make sure we're clean
            self.cleanup()
            return

        def _get_date(date):
            """Get the dateTime from date or dateTime as a local."""
            if 'date' in date:
                return dt.start_of_local_day(dt.dt.datetime.combine(
                    dt.parse_date(date['date']), dt.dt.time.min))
            else:
                return dt.as_local(dt.parse_datetime(date['dateTime']))

        start = _get_date(self.data.event['start'])
        end = _get_date(self.data.event['end'])

        summary = self.data.event.get('summary', '')

        # check if we have an offset tag in the message
        # time is HH:MM or MM
        reg = '{}([+-]?[0-9]{{0,2}}(:[0-9]{{0,2}})?)'.format(self._offset)
        search = re.search(reg, summary)
        if search and search.group(1):
            time = search.group(1)
            if ':' not in time:
                if time[0] == '+' or time[0] == '-':
                    time = '{}0:{}'.format(time[0], time[1:])
                else:
                    time = '0:{}'.format(time)

            offset_time = time_period_str(time)
            summary = (summary[:search.start()] + summary[search.end():]) \
                .strip()
        else:
            offset_time = dt.dt.timedelta()  # default it

        # cleanup the string so we don't have a bunch of double+ spaces
        self._cal_data['message'] = re.sub('  +', '', summary).strip()

        self._cal_data['offset_time'] = offset_time
        self._cal_data['location'] = self.data.event.get('location', '')
        self._cal_data['description'] = self.data.event.get('description', '')
        self._cal_data['start'] = start
        self._cal_data['end'] = end
        self._cal_data['all_day'] = 'date' in self.data.event['start']
コード例 #15
0
ファイル: __init__.py プロジェクト: zhangziran/common_timer
 def insert(self,
            task_id,
            duration,
            callback,
            operation='turn_off',
            **kwargs):
     """ add new task into queue """
     if duration == "0:00:00":
         return None
     second = time_period_str(duration).total_seconds()
     loop = second / len(self.__queue)
     slot = (second + self.__current_slot - 1) % len(self.__queue)
     delayQueueTask = DelayQueueTask(task_id,
                                     operation,
                                     int(slot),
                                     loop,
                                     callback,
                                     kwargs=kwargs)
     self.__queue[delayQueueTask.slot].append(delayQueueTask)
     _LOGGER.debug("create task:{}/{}".format(delayQueueTask.slot,
                                              delayQueueTask.loop))
     return delayQueueTask
コード例 #16
0
def extract_offset(summary: str,
                   offset_prefix: str) -> tuple[str, datetime.timedelta]:
    """Extract the offset from the event summary.

    Return a tuple with the updated event summary and offset time.
    """
    # check if we have an offset tag in the message
    # time is HH:MM or MM
    reg = f"{offset_prefix}([+-]?[0-9]{{0,2}}(:[0-9]{{0,2}})?)"
    search = re.search(reg, summary)
    if search and search.group(1):
        time = search.group(1)
        if ":" not in time:
            if time[0] == "+" or time[0] == "-":
                time = f"{time[0]}0:{time[1:]}"
            else:
                time = f"0:{time}"

        offset_time = time_period_str(time)
        summary = (summary[:search.start()] + summary[search.end():]).strip()
        return (summary, offset_time)
    return (summary, datetime.timedelta())
コード例 #17
0
async def test_set_auto_off_service(hass, mock_bridge, mock_api):
    """Test the set auto off service."""
    await init_integration(hass)
    assert mock_bridge

    device = DUMMY_WATER_HEATER_DEVICE
    entity_id = f"{SWITCH_DOMAIN}.{slugify(device.name)}"

    with patch(
            "homeassistant.components.switcher_kis.switch.SwitcherApi.set_auto_shutdown"
    ) as mock_set_auto_shutdown:
        await hass.services.async_call(
            DOMAIN,
            SERVICE_SET_AUTO_OFF_NAME,
            {
                ATTR_ENTITY_ID: entity_id,
                CONF_AUTO_OFF: DUMMY_AUTO_OFF_SET
            },
            blocking=True,
        )

        assert mock_api.call_count == 2
        mock_set_auto_shutdown.assert_called_once_with(
            time_period_str(DUMMY_AUTO_OFF_SET))
コード例 #18
0
    def _restore_state(self, restored_state, state_attributes) -> None:
        if restored_state not in VIABLE_STATUSES:
            self._state = STATUS_IDLE

        self._state = restored_state

        # restore last duration if config doesn't have a default
        if not self._config[CONF_DURATION] \
           and not state_attributes.get(ATTR_DURATION) == "None":
            try:
                duration_data = list(
                    map(int,
                        str(state_attributes.get(ATTR_DURATION)).split(":")))
                self._config[CONF_DURATION] = timedelta(
                    hours=duration_data[0],
                    minutes=duration_data[1],
                    seconds=duration_data[2])
            except ValueError:
                self._config[CONF_DURATION] = timedelta(DEFAULT_DURATION)
            self._duration = cv.time_period_str(config[CONF_DURATION])

        # restore remaining (needed for paused state)
        if self._state == STATUS_PAUSED \
           and not state_attributes.get(ATTR_REMAINING) == "None" \
           and not state_attributes.get(ATTR_REMAINING) == str(timedelta()):
            try:
                remaining_dt = list(
                    map(int,
                        str(state_attributes.get(ATTR_REMAINING)).split(":")))
                self._remaining = timedelta(hours=remaining_dt[0],
                                            minutes=remaining_dt[1],
                                            seconds=remaining_dt[2])
            except ValueError:
                self._remaining = self._duration
        else:
            self._remaining = timedelta()

        # restore end time
        try:
            if state_attributes.get(ATTR_FINISHES_AT) is not None:
                self._end = datetime.strptime(
                    state_attributes.get(ATTR_FINISHES_AT),
                    "%Y-%m-%d %H:%M:%S%z")
            else:
                self._end = None
        except ValueError:
            self._end = None

        # timer was active
        if self._state == STATUS_ACTIVE:
            try:
                # account for lost time
                if self._end:
                    self._remaining = self._end - dt_util.utcnow().replace(
                        microsecond=0)
                else:
                    self._remaining = timedelta()
                _LOGGER.debug("%s : Restored remaining: %s",
                              self._config.get(CONF_NAME),
                              _format_timedelta(self._remaining))

                # only restore if restore_grace_period not exceeded
                if self._remaining + self._restore_grace_period >= timedelta():
                    self._state = STATUS_PAUSED
                    self._end = None
                    self.async_start(None)
                else:
                    self._state = STATUS_IDLE
            except ValueError:
                self._remaining = timedelta()
                self._end = None
                self._state = STATUS_IDLE
コード例 #19
0
ファイル: media.py プロジェクト: nickovs/home-assistant
def _timespan_secs(timespan: str | None) -> None | float:
    """Parse a time-span into number of seconds."""
    if timespan in UNAVAILABLE_VALUES:
        return None
    return time_period_str(timespan).total_seconds()  # type: ignore[arg-type]
コード例 #20
0
 async def async_update_config(self, config: dict) -> None:
     """Handle when the config is updated."""
     self._config = config
     self._duration = cv.time_period_str(config[CONF_DURATION])
     self.async_write_ha_state()