- 
                Notifications
    You must be signed in to change notification settings 
- Fork 59
Writing an App in Pyscript
        Daniel Lashua edited this page Oct 18, 2020 
        ·
        5 revisions
      
    So you've got a pyscript doing a thing, and you realize you want to do that same thing, but with different inputs and outputs. You can just copy the code and change all the entity_ids, over and over each time you need it. For really simple scripts, sometimes, this is the best route.
But, another option: turn it into an app!
Here's an example with heavily commented code to show you what the conversion might look like.
@state_trigger("binary_sensor.room1 == 'on'")
def motion_light():
    task.unique("motion_light")
    if light.room1 != "on":
        light.turn_on(entity_id="light.room1")
    task.sleep(float(input_number.room1))
    light.turn_off(entity_id="light.room1")pyscript:
  apps:
    motion_lights:
      - motion_id: binary_sensor.room1
        light_id: light.room1
        time_id: input_number.room1
      - motion_id: binary_sensor.room2
        light_id: light.room2
        time_id: input_number.room1# we'll use this later
registered_triggers = []
# First, we define a function that makes more functions.
def make_motion_light(config):
    # this is the original code modified to 
    # substituting in the variables from YAML.
    # compare it line by line with the original code
    # replace the hardcoded entity ID with the value from config
    @state_trigger(f"{config['motion_id']} == 'on'")
    def motion_light():
        # we want a unique task for each separate app, so lets use
        # a unique name based on some config data
        task.unique(f"motion_light_{config['motion_id']}")
        # because our light entity is in a variable we'll have to
        # use the longer form to get the state
        if state.get(config['light_id']) != "on":
            # substitute in the value from config
            light.turn_on(entity_id=config['light_id'])
        # substitute from config    
        task.sleep(float(state.get(config['time_id'])))
        # substitute from config
        light.turn_off(entity_id=config['light_id'])
    # now that we've made a function specifically for this config item
    # we need to register it in the global scope so pyscript sees it.
    # the easiest way to do that is add it to a global list.
    registered_triggers.append(motion_light)
# now we need some code that runs at startup and processes the YAML configuration.
# I've written a function for this that you can paste anywhere.
# It takes two parameters.
#
# 1) The YAML key for this app directly under the "apps" key.
#
# 2) The function to call that will create another function for each specific app
def load_apps(app_name, factory):
    if "apps" not in pyscript.config:
        return
    
    if app_name not in pyscript.config['apps']:
        return
    for app in pyscript.config['apps'][app_name]:
        factory(app)
# now we just need the startup trigger
@time_trigger('startup')
def motion_light_startup():
    load_apps("motion_lights", make_motion_light)