예제 #1
0
파일: script.py 프로젝트: fabiandevia/home
def call_from_config(hass: HomeAssistant,
                     config: ConfigType,
                     variables: Optional[Sequence] = None,
                     context: Optional[Context] = None) -> None:
    """Call a script based on a config entry."""
    Script(hass, cv.SCRIPT_SCHEMA(config)).run(variables, context)
예제 #2
0
async def test_multiple_runs_no_wait(hass, script_mode):
    """Test multiple runs with no wait in script."""
    logger = logging.getLogger("TEST")
    calls = []
    heard_event = asyncio.Event()

    async def async_simulate_long_service(service):
        """Simulate a service that takes a not insignificant time."""
        fire = service.data.get("fire")
        listen = service.data.get("listen")
        service_done = asyncio.Event()

        @callback
        def service_done_cb(event):
            logger.debug("simulated service (%s:%s) done", fire, listen)
            service_done.set()

        calls.append(service)
        logger.debug("simulated service (%s:%s) started", fire, listen)
        unsub = hass.bus.async_listen(listen, service_done_cb)
        hass.bus.async_fire(fire)
        await service_done.wait()
        unsub()

    hass.services.async_register("test", "script", async_simulate_long_service)

    @callback
    def heard_event_cb(event):
        logger.debug("heard: %s", event)
        heard_event.set()

    sequence = cv.SCRIPT_SCHEMA([
        {
            "service": "test.script",
            "data_template": {
                "fire": "{{ fire1 }}",
                "listen": "{{ listen1 }}"
            },
        },
        {
            "service": "test.script",
            "data_template": {
                "fire": "{{ fire2 }}",
                "listen": "{{ listen2 }}"
            },
        },
    ])
    script_obj = script.Script(hass, sequence, script_mode=script_mode)

    # Start script twice in such a way that second run will be started while first run
    # is in the middle of the first service call.

    unsub = hass.bus.async_listen("1", heard_event_cb)
    logger.debug("starting 1st script")
    hass.async_create_task(
        script_obj.async_run({
            "fire1": "1",
            "listen1": "2",
            "fire2": "3",
            "listen2": "4"
        }))
    await asyncio.wait_for(heard_event.wait(), 1)
    unsub()

    logger.debug("starting 2nd script")
    await script_obj.async_run({
        "fire1": "2",
        "listen1": "3",
        "fire2": "4",
        "listen2": "4"
    })
    await hass.async_block_till_done()

    assert len(calls) == 4
예제 #3
0
async def test_script_mode_queue(hass):
    """Test overlapping runs with script_mode='queue'."""
    event = "test_event"
    events = async_capture_events(hass, event)
    sequence = cv.SCRIPT_SCHEMA([
        {
            "event": event,
            "event_data": {
                "value": 1
            }
        },
        {
            "wait_template": "{{ states.switch.test.state == 'off' }}"
        },
        {
            "event": event,
            "event_data": {
                "value": 2
            }
        },
        {
            "wait_template": "{{ states.switch.test.state == 'on' }}"
        },
    ])
    logger = logging.getLogger("TEST")
    script_obj = script.Script(hass,
                               sequence,
                               script_mode="queue",
                               logger=logger)
    wait_started_flag = async_watch_for_action(script_obj, "wait")

    try:
        hass.states.async_set("switch.test", "on")
        hass.async_create_task(script_obj.async_run())
        await asyncio.wait_for(wait_started_flag.wait(), 1)

        assert script_obj.is_running
        assert len(events) == 1
        assert events[0].data["value"] == 1

        # Start second run of script while first run is suspended in wait_template.
        # This second run should not start until the first run has finished.

        hass.async_create_task(script_obj.async_run())

        await asyncio.sleep(0)
        assert script_obj.is_running
        assert len(events) == 1

        wait_started_flag.clear()
        hass.states.async_set("switch.test", "off")
        await asyncio.wait_for(wait_started_flag.wait(), 1)

        assert script_obj.is_running
        assert len(events) == 2
        assert events[1].data["value"] == 2

        wait_started_flag.clear()
        hass.states.async_set("switch.test", "on")
        await asyncio.wait_for(wait_started_flag.wait(), 1)

        await asyncio.sleep(0)
        assert script_obj.is_running
        assert len(events) == 3
        assert events[2].data["value"] == 1
    except (AssertionError, asyncio.TimeoutError):
        await script_obj.async_stop()
        raise
    else:
        hass.states.async_set("switch.test", "off")
        await asyncio.sleep(0)
        hass.states.async_set("switch.test", "on")
        await hass.async_block_till_done()

        assert not script_obj.is_running
        assert len(events) == 4
        assert events[3].data["value"] == 2
예제 #4
0
async def test_script_mode_2(hass, caplog, script_mode, messages, last_events):
    """Test overlapping runs with script_mode='restart'."""
    event = "test_event"
    events = async_capture_events(hass, event)
    sequence = cv.SCRIPT_SCHEMA([
        {
            "event": event,
            "event_data": {
                "value": 1
            }
        },
        {
            "wait_template": "{{ states.switch.test.state == 'off' }}"
        },
        {
            "event": event,
            "event_data": {
                "value": 2
            }
        },
    ])
    logger = logging.getLogger("TEST")
    script_obj = script.Script(hass,
                               sequence,
                               script_mode=script_mode,
                               logger=logger)
    wait_started_flag = async_watch_for_action(script_obj, "wait")

    try:
        hass.states.async_set("switch.test", "on")
        hass.async_create_task(script_obj.async_run())
        await asyncio.wait_for(wait_started_flag.wait(), 1)

        assert script_obj.is_running
        assert len(events) == 1
        assert events[0].data["value"] == 1

        # Start second run of script while first run is suspended in wait_template.
        # This should stop first run then start a new run.

        wait_started_flag.clear()
        hass.async_create_task(script_obj.async_run())
        await asyncio.wait_for(wait_started_flag.wait(), 1)

        assert script_obj.is_running
        assert len(events) == 2
        assert events[1].data["value"] == 1
        assert all(
            any(rec.levelname == "INFO" and rec.name == "TEST"
                and message in rec.message for rec in caplog.records)
            for message in messages)
    except (AssertionError, asyncio.TimeoutError):
        await script_obj.async_stop()
        raise
    else:
        hass.states.async_set("switch.test", "off")
        await hass.async_block_till_done()

        assert not script_obj.is_running
        assert len(events) == 2 + len(last_events)
        for idx, value in enumerate(last_events, start=2):
            assert events[idx].data["value"] == value
예제 #5
0
async def test_repeat_nested(hass, variables, first_last, inside_x):
    """Test nested repeats."""
    event = "test_event"
    events = async_capture_events(hass, event)

    sequence = cv.SCRIPT_SCHEMA(
        [
            {
                "event": event,
                "event_data_template": {
                    "repeat": "{{ None if repeat is not defined else repeat }}",
                    "x": "{{ None if x is not defined else x }}",
                },
            },
            {
                "repeat": {
                    "count": 2,
                    "sequence": [
                        {
                            "event": event,
                            "event_data_template": {
                                "first": "{{ repeat.first }}",
                                "index": "{{ repeat.index }}",
                                "last": "{{ repeat.last }}",
                                "x": "{{ None if x is not defined else x }}",
                            },
                        },
                        {
                            "repeat": {
                                "count": 2,
                                "sequence": {
                                    "event": event,
                                    "event_data_template": {
                                        "first": "{{ repeat.first }}",
                                        "index": "{{ repeat.index }}",
                                        "last": "{{ repeat.last }}",
                                        "x": "{{ None if x is not defined else x }}",
                                    },
                                },
                            }
                        },
                        {
                            "event": event,
                            "event_data_template": {
                                "first": "{{ repeat.first }}",
                                "index": "{{ repeat.index }}",
                                "last": "{{ repeat.last }}",
                                "x": "{{ None if x is not defined else x }}",
                            },
                        },
                    ],
                }
            },
            {
                "event": event,
                "event_data_template": {
                    "repeat": "{{ None if repeat is not defined else repeat }}",
                    "x": "{{ None if x is not defined else x }}",
                },
            },
        ]
    )
    script_obj = script.Script(hass, sequence, "test script")

    with mock.patch(
        "homeassistant.helpers.condition._LOGGER.error",
        side_effect=AssertionError("Template Error"),
    ):
        await script_obj.async_run(variables)

    assert len(events) == 10
    assert events[0].data == first_last
    assert events[-1].data == first_last
    for index, result in enumerate(
        (
            ("True", "1", "False", inside_x),
            ("True", "1", "False", inside_x),
            ("False", "2", "True", inside_x),
            ("True", "1", "False", inside_x),
            ("False", "2", "True", inside_x),
            ("True", "1", "False", inside_x),
            ("False", "2", "True", inside_x),
            ("False", "2", "True", inside_x),
        ),
        1,
    ):
        assert events[index].data == {
            "first": result[0],
            "index": result[1],
            "last": result[2],
            "x": result[3],
        }
예제 #6
0
async def test_repeat_conditional(hass, condition):
    """Test repeat action w/ while option."""
    event = "test_event"
    events = async_capture_events(hass, event)
    count = 3

    sequence = {
        "repeat": {
            "sequence": [
                {
                    "event": event,
                    "event_data_template": {
                        "first": "{{ repeat.first }}",
                        "index": "{{ repeat.index }}",
                    },
                },
                {
                    "wait_template": "{{ is_state('sensor.test', 'next') }}"
                },
                {
                    "wait_template":
                    "{{ not is_state('sensor.test', 'next') }}"
                },
            ],
        }
    }
    if condition == "while":
        sequence["repeat"]["while"] = {
            "condition": "template",
            "value_template": "{{ not is_state('sensor.test', 'done') }}",
        }
    else:
        sequence["repeat"]["until"] = {
            "condition": "template",
            "value_template": "{{ is_state('sensor.test', 'done') }}",
        }
    script_obj = script.Script(hass, cv.SCRIPT_SCHEMA(sequence))

    wait_started = async_watch_for_action(script_obj, "wait")
    hass.states.async_set("sensor.test", "1")

    hass.async_create_task(script_obj.async_run())
    try:
        for index in range(2, count + 1):
            await asyncio.wait_for(wait_started.wait(), 1)
            wait_started.clear()
            hass.states.async_set("sensor.test", "next")
            await asyncio.wait_for(wait_started.wait(), 1)
            wait_started.clear()
            hass.states.async_set("sensor.test", index)
        await asyncio.wait_for(wait_started.wait(), 1)
        hass.states.async_set("sensor.test", "next")
        await asyncio.wait_for(wait_started.wait(), 1)
        wait_started.clear()
        hass.states.async_set("sensor.test", "done")
        await asyncio.wait_for(hass.async_block_till_done(), 1)
    except asyncio.TimeoutError:
        await script_obj.async_stop()
        raise

    assert len(events) == count
    for index, event in enumerate(events):
        assert event.data.get("first") == str(index == 0)
        assert event.data.get("index") == str(index + 1)