Blueprint for packages

so it could possible to create a package just using (i.e.) prefixes/suffixes passed to a blueprint instead of editing the package of every similar device…

thanks

Vote this up as it would be the ultimate way of creating solutions that span multiple types of resources that need to interact with each other (sensors / scripts / automations) with very little input from the user.

An example would be my blueprint for the sunrise alarm that requires an automation and a script, and would also benefit from a template sensor, but each currently needs to be deployed separately and requires 3 individual blueprints.

What do you mean by a package?
In general, a package could be a dictionary like

input_boolean:
  …
template:
  …
automation:
  …

or a list like:

- sensor:
    - name: …
      …
    - name: …
      …
- binary_sensor:
    - name: …
      …
    - name: …
      …

Hi steriku or Pietro,

This isn’t even a Feature request. We appear to be asking a question (that I don’t understand, even).

TBH I should move this to some other catagory.

Please elaborate, assuming you know, what the request actually is.

Feature Request Guidelines 📔.

you have a package where you put sensor definition for a device, automations, scripts or whatever you want; you use a package to keep all the code for a device separated from others… and this could be big… now, repeat for n devices, clear it is a lot of work; workaround: use snippets or replace names, time consuming when you need to make modifications to the yaml code… you could use blueprint and pass a string/variable/whatever to be replaced, just as you do with automations… it is fast

(no one interested so i’m using a combination of snippets and string replacement now)

Blueprints should have done this from the beginning

Currently if we want to deploy an automation blueprint that requires other resources such as scripts, template sensors or helpers we have to create blueprints separately. One for the automation, one for the script and now we can use templates., but there is no link between them. If the blueprint requries a helper or script we have to have the user create the resources manually or import a script/template blueprint and have inputs to the automation blueprint where the user can provide what they created.

A package blueprint would allow for us to create all of these for the user and link them within the blueprint so there is much less interaction for the user. They provide the base inputs and the automation, scripts, template sensors and helpers are created for them and linked to each other within the package blueprint. It would just require a way to prevent duplicate names/ids on each of the resources if you want to create multiple deployed instances of the package blueprint.

An example of this is a package I’ve created for my pool pump which is controlled by solar heater temperatures. There is simply no way to easily pass this functionality on to the community because of the tight integrations of all the individual components.

sensor:
  - platform: history_stats # used to track how long the pump has been on today
    name: Pool Pump On Time
    entity_id: switch.pool_pump
    unique_id: pool_pump_on_time
    state: "on"
    type: time
    start: "{{ today_at() }}"
    end: "{{ now() }}"
  - platform: history_stats # used to track how long the pump has been on today
    name: Pool Solar On Time
    entity_id: sensor.pool_solar_temp_trigger
    unique_id: pool_solar_on_time
    state: "on"
    type: time
    start: "{{ today_at() }}"
    end: "{{ now() }}"
  - platform: statistics # Used for info on dashboard
    name: "Pool 24h Temp Change"
    entity_id: sensor.pool_monitor_pool_water_temperature
    state_characteristic: change
    max_age:
      hours: 24
  - platform: derivative # used for info on dashboard
    source: sensor.pool_solar_temp_trend
    name: Pool Solar Temp Trend
    round: 2
    unit_time: h
    time_window: "00:10:00"
  - platform: derivative # used for info on dashboard
    source: sensor.pool_monitor_pool_water_temperature
    name: Pool Water Temp Trend
    round: 2
    unit_time: h
    time_window: "00:20:00"

timer:
  pool_pump_timer: # used in pool schedule script
    name: Pool Pump Timer
    duration: 0:30:00
    restore: true
  pool_pump_minimum_run_time: # used in schedule script so pump will run for at least this time (not flicker on/off)
    name: Pool Pump Minimum Run Time
    duration: 0:05:00

input_boolean:
  # used for toggle electrical plugs for valves
  solar_toggle:
    name: Solar Toggle
  # used to track if pump forced on to meet minimum time, currently for display
  enforce_pool_pump_minimum_time:
    name: Enforce Pool Pump Minimum time
  # prevent pump from coming on with schedule script
  pool_timer_disable:
    name: Pool Timer Disable

input_number:
  pool_pump_stop_deadline_offset_from_sunset: # pump should finish it's full run time at or before this offset from sunet
    name: Pool Pump Stop Deadline Offset from Sunset
    initial: -2
    min: -6
    max: 2
    step: 0.5
    mode: box
  pool_run_time: # run pump for this time per day
    name: Pool Run Time
    initial: 8
    min: 1
    max: 12
    step: 1
    mode: box
  pool_temp_offset: # used to create a neutral zone around the solar trigger time, prevent pump from flickering on off
    name: Pool Temp Offset
    initial: 0.2
    min: 0
    max: 1
    step: 0.1
    mode: box

template:
  - binary_sensor:
      - name: Pool Pump Time Met # track whether Pool Run Time has been met, used in many places
        state: >-
          {{ states('sensor.pool_pump_on_time') | float * 3600 >= states('input_number.pool_run_time') | float * 3600 }}
  - sensor:
      - name: Pool Solar Temp Trigger # calculate the trigger for the pump to enable the solar heater
        state: >-
          {% if states('sensor.pool_monitor_pool_solar_heater_temperature') |float > 
          states('sensor.pool_monitor_pool_water_temperature') | float + 
          states('input_number.pool_temp_offset') | float  %}
            on
          {%- elif states('sensor.pool_monitor_pool_solar_heater_temperature') | float  <
          states('sensor.pool_monitor_pool_water_temperature') | float - 
          states('input_number.pool_temp_offset') | float  %}
            off
          {%- else %}
            neutral
          {%- endif %}
      - name: Pool Time Met Percent # info for dashboard
        state: >-
          {{
            ((states('sensor.pool_pump_on_time') | float * 3600) / (states('input_number.pool_run_time') | float * 3600)  * 100) | round(2)
          }}
      - name: Pool Time Before Sunset # calculate time left before sunset offset
        state: >-
          {% set t = (states('sensor.sun_next_setting')| as_datetime | as_local ).strftime('%Y-%m-%d') %}
          {% set n = (now().strftime('%Y-%m-%d')) %}
          {%- if t == n %}
            {{ (((as_timestamp(states('sensor.sun_next_setting')) - as_timestamp(now())| float) + 
            (states('input_number.pool_pump_stop_deadline_offset_from_sunset') |float * 3600)) / 3600) | round(2) }}
          {% else %}
            0.0
          {% endif %}
      - name: Pool Time Before Deadline # calculate whether pump should be forced on to finish minimum run time
        state: >-
          {{ (states('sensor.pool_time_before_sunset') | float * 3600)  | timestamp_custom('%H:%M', false)}}
      - name: Pool Time Left # how much longer the pump nees to run to meet minimum run time
        state: >-
          {% if (states('input_number.pool_run_time') | float - 
            states('sensor.pool_pump_on_time') | float) | round(2) > 0 %}
            {{ (states('input_number.pool_run_time') | float - 
            states('sensor.pool_pump_on_time') | float) | round(2) }}
          {%- else %}
            0.0
          {%- endif %}
      - name: Pool Pump Time Remaining # used for dashboard
        state: >-
          {{ (states('sensor.pool_time_left') | float * 3600)  | timestamp_custom('%H:%M', false)}}
      - name: Solar Differencial # how much warmer the solar is than the water, used for dashboard
        state: >-
          {{ (states('sensor.pool_monitor_pool_solar_heater_temperature') | float - 
          states('sensor.pool_monitor_pool_water_temperature') | float ) | round(2) }}
        unit_of_measurement: "°C"
        state_class: measurement
      - name: Pool F Temperature # used for dashboard
        state: "{{ ((states('sensor.pool_monitor_pool_water_temperature') | float ) * (9/5) + 32) | round(2) }}"
        unit_of_measurement: "°F"
        state_class: measurement
      - name: Pool Pump on Time Format # formatted time for dashboard
        state: "{{ ((states('sensor.pool_pump_on_time') | int * 3600) + ((states('sensor.pool_pump_on_time') | float  * 60 % 60) |int * 60 )) | timestamp_custom('%H:%M', false) }}"
      - name: Pool Solar on Timestamp # formatted time for dashboard
        state: "{{ ((states('sensor.pool_solar_on_time') | int * 3600) + ((states('sensor.pool_solar_on_time') | float  * 60 % 60) |int * 60 )) | timestamp_custom('%H:%M', false) }}"
        unique_id: pool_solar_on_timestamp

script:
  pool_scheduler:
    alias: Pool Pump Scheduler
    trace:
      stored_traces: 50
    description: Check if pool needs to run to meet daily minimum and starts a timer if need be
    fields:
      action:
        description: Takes action from input (neutral, off)
    sequence:
      - if:
          - condition: and
            conditions:
              # check against desired stop time
              - "{{ states('input_number.pool_run_time') | float - states('sensor.pool_pump_on_time') | float > states('sensor.pool_time_before_sunset') | float }}"
              # timer is not on, may have been set for maintenance
              - "{{ states('timer.pool_pump_timer') != 'active' }}"
              # check whether desired runtime has been met
              - "{{ states('binary_sensor.pool_pump_time_met') == 'off' }}"
              # check whether pump disable toggle has been turn on
              - "{{ states('input_boolean.pool_timer_disable') != 'on' }}"
        then:
          - service: timer.start
            data:
              duration: "{{ (states('input_number.pool_run_time') | float * 3600) - (states('sensor.pool_pump_on_time') |float * 3600) }}"
            target:
              entity_id: timer.pool_pump_timer
        else:
          - if:
              condition: and
              conditions:
                - "{{ states('switch.pool_pump') == 'on' }}"
                - "{{ states('timer.pool_pump_minimum_run_time') != 'active' }}"
                - "{{ states('timer.pool_pump_timer') != 'active' }}"
            then:
              - service: switch.turn_off
                target:
                  entity_id:
                    - switch.pool_pump
    mode: single

  pool_solar_toggle: # script to put plugs that control valves in proper confuration for toggling solar
    alias: Pool Solar Toggle
    description: Toggle the 2 valves for the solar heater
    trace:
      stored_traces: 30
    fields:
      action:
        description: Takes action from input (on, off)
    variables:
      toggle_action: "{{ action }}"
    sequence:
      - if:
          - "{{ toggle_action == 'on' }}"
        then:
          - service: switch.turn_on
            metadata: {}
            data: {}
            target:
              entity_id: switch.solar_bypass_valve
          - service: switch.turn_off
            metadata: {}
            data: {}
            target:
              entity_id: switch.solar_return_valve
        else:
          - service: switch.turn_off
            metadata: {}
            data: {}
            target:
              entity_id: switch.solar_bypass_valve
          - service: switch.turn_on
            metadata: {}
            data: {}
            target:
              entity_id: switch.solar_return_valve

  cancel_and_disable_timer_script:
    alias: Cancel and Disable Timer Script
    sequence:
      - if:
          - "{{ states('timer.pool_pump_timer') == 'active' }}"
        then:
          - service: timer.cancel
            target:
              entity_id: timer.pool_pump_timer
      - service: input_boolean.toggle
        target:
          entity_id: input_boolean.pool_timer_disable

automation:
  # triggerd by toggle to control 2 valves as one
  - alias: Solar Toggle
    mode: single
    trigger:
      - platform: state
        entity_id:
          - input_boolean.solar_toggle
    condition: []
    action:
      - if:
          - "{{ states('input_boolean.solar_toggle') == 'on' }}"
        then:
          - service: script.pool_solar_toggle
            metadata: {}
            data:
              action: "on"
        else:
          - service: script.pool_solar_toggle
            metadata: {}
            data:
              action: "off"
  # used for maintenance to force pump to be forced on and kept on, timer triggerd on by dashboard button
  - alias: Pool Pump Timer
    description: ""
    trigger:
      - platform: event
        event_type: timer.started
        event_data:
          entity_id: timer.pool_pump_timer
        id: Timer Start
      - platform: event
        event_type: timer.finished
        event_data:
          entity_id: timer.pool_pump_timer
        id: Timer Finished
    condition: []
    action:
      - choose:
          - conditions:
              - condition: trigger
                id: Timer Start
            sequence:
              - service: switch.turn_on
                data: {}
                target:
                  entity_id: switch.pool_pump
          - conditions:
              - condition: trigger
                id: Timer Finished
            sequence:
              - service: switch.turn_off
                data: {}
                target:
                  entity_id: switch.pool_pump
    mode: single
1 Like

All right, that makes sense. What I don’t understand is if it’s such a great idea, it has only 1 vote in 16 months, so not very popular.
Ah, it was already requested, so this is a duplicate…
Extend Blueprints to include Helpers, multiple Automations/Scripts and Lovelace.
and
Blueprints in packages
and
"Blueprints" for components/integrations.

Please vote there. The first one has 88 votes, it sounds like the most popular…

This would be a boon to help less technical people get complex functionality from HA, without having to ‘yaml up’ or navigate multple pages in the webiste for implementation and decrease mental load of how the components need to interact with each other.

My guess is that packages are a lesser known feature of HA, but they could be very powerful if fronted by a blueprint.

Fine. Move your vote and comments to the earliest Feature Request as duplicates are likely to be closed.

Packages are a yaml-based feature which does not conform to a current trend to move a config to UI (which I do not appreciate myself since some features are only supported in UI and stop being supported in yaml).

Since I am using packages extensively and many packages are similar - my way of “blueprinting” packages is as follows:

  1. Using “Dev tools - Template”, create a jinja code which GENERATES a package for some predefined variables like “device”, “integration” etc.
  2. This jinja code (let’s call it “meta package”) save in some file like “xxxxx.gen” (“generator”), and the generated code for a particular defined variables is your ready standard package.

I understand why the push is for UI configuration but we can’t discount the advanced functionality that yaml gives us. We need to maintain both approaches.

Just look at the Infrastructure as Code movement that all cloud service providers know is essential. It allows reproducibility and dependancy management that just can’t be replicated via UI.

Closed as dup of Extend Blueprints to include Helpers, multiple Automations/Scripts and Lovelace