Any way to DRY YAML?

DRY = Don’t repeat yourself. Well, you can see how much repetition is going on here! Looking to simplify. Is there a way to use variables in YAML? I was thinking about using PHP to generate my configuration.yaml? Any suggestions appreciated!

rest:
  - resource: https://cmg-prod.apigee.net/v1/xapi/tvschedules/tvguide/9100006621/web?&duration=480
    method: GET
    sensor:
      - name: TV Guide NBC
        value_template: 'OK'
        json_attributes_path: "$.data.items[2]"
        json_attributes: &tv_guide_json_attributes
          - channel
          - programSchedules
      - name: TV Guide FOX
        value_template: 'OK'
        json_attributes_path: "$.data.items[3]"
        json_attributes: *tv_guide_json_attributes
      - name: TV Guide ABC
        value_template: 'OK'
        json_attributes_path: "$.data.items[1]"
        json_attributes: *tv_guide_json_attributes
      - name: TV Guide PBS Create
        value_template: 'OK'
        json_attributes_path: "$.data.items[178]"
        json_attributes: *tv_guide_json_attributes

template:
  - sensor:
      name: PBS Create Shows
      unique_id: pbs-create-shows
      state: 'OK'
      attributes:
        titles: >-
          [ {%- for i in range(0,((states.sensor.tv_guide_pbs_create.attributes.programSchedules | to_json(ensure_ascii=False)) | from_json()) | count) -%}
            '{{ ((states.sensor.tv_guide_pbs_create.attributes.programSchedules | to_json(ensure_ascii=False)) | from_json())[i]['title'] | replace("'","\\'") }}'
            {%- if not loop.last %},{% endif -%}
            {% endfor -%} ]
        start_times: >-
          [ {%- for i in range(0,((states.sensor.tv_guide_pbs_create.attributes.programSchedules | to_json(ensure_ascii=False)) | from_json()) | count) -%}
          {{ ((states.sensor.tv_guide_pbs_create.attributes.programSchedules | to_json(ensure_ascii=False)) | from_json())[i]['startTime'] }}
          {%- if not loop.last %},{% endif -%}
          {% endfor -%} ]
        end_times: >-
          [ {%- for i in range(0,((states.sensor.tv_guide_pbs_create.attributes.programSchedules | to_json(ensure_ascii=False)) | from_json()) | count) -%}
          {{ ((states.sensor.tv_guide_pbs_create.attributes.programSchedules | to_json(ensure_ascii=False)) | from_json())[i]['endTime'] }}
          {%- if not loop.last %},{% endif -%}
          {% endfor -%} ]          
  - sensor:
      - name: FOX Shows
        unique_id: fox-shows
        state: 'OK'
        attributes:
          titles: >-
            [ {%- for i in range(0,((states.sensor.tv_guide_nbc.attributes.programSchedules | to_json(ensure_ascii=False)) | from_json()) | count) -%}
            '{{ ((states.sensor.tv_guide_fox.attributes.programSchedules | to_json(ensure_ascii=False)) | from_json())[i]['title'] | replace("'","\\'") }}'
            {%- if not loop.last %},{% endif -%}
            {% endfor -%} ]
          start_times: >-
            [ {%- for i in range(0,((states.sensor.tv_guide_fox.attributes.programSchedules | to_json(ensure_ascii=False)) | from_json()) | count) -%}
            {{ ((states.sensor.tv_guide_fox.attributes.programSchedules | to_json(ensure_ascii=False)) | from_json())[i]['startTime'] }}
            {%- if not loop.last %},{% endif -%}
            {% endfor -%} ]
          end_times: >-
            [ {%- for i in range(0,((states.sensor.tv_guide_fox.attributes.programSchedules | to_json(ensure_ascii=False)) | from_json()) | count) -%}
            {{ ((states.sensor.tv_guide_fox.attributes.programSchedules | to_json(ensure_ascii=False)) | from_json())[i]['endTime'] }}
            {%- if not loop.last %},{% endif -%}
            {% endfor -%} ]            
  - sensor:
      - name: NBC Shows
        unique_id: nbc-shows
        state: 'OK'
        attributes:
          titles: >-
            [ {%- for i in range(0,((states.sensor.tv_guide_nbc.attributes.programSchedules | to_json(ensure_ascii=False)) | from_json()) | count) -%}
            '{{ ((states.sensor.tv_guide_nbc.attributes.programSchedules | to_json(ensure_ascii=False)) | from_json())[i]['title'] | replace("'","\\'") }}'
            {%- if not loop.last %},{% endif -%}
            {% endfor -%} ]
          start_times: >-
            [ {%- for i in range(0,((states.sensor.tv_guide_nbc.attributes.programSchedules | to_json(ensure_ascii=False)) | from_json()) | count) -%}
            {{ ((states.sensor.tv_guide_nbc.attributes.programSchedules | to_json(ensure_ascii=False)) | from_json())[i]['startTime'] }}
            {%- if not loop.last %},{% endif -%}
            {% endfor -%} ]
          end_times: >-
            [ {%- for i in range(0,((states.sensor.tv_guide_nbc.attributes.programSchedules | to_json(ensure_ascii=False)) | from_json()) | count) -%}
            {{ ((states.sensor.tv_guide_nbc.attributes.programSchedules | to_json(ensure_ascii=False)) | from_json())[i]['endTime'] }}
            {%- if not loop.last %},{% endif -%}
            {% endfor -%} ]            
  - sensor:
      - name: ABC Shows
        unique_id: abc-shows
        state: 'OK'
        attributes:
          titles: >-
            [ {%- for i in range(0,((states.sensor.tv_guide_abc.attributes.programSchedules | to_json(ensure_ascii=False)) | from_json()) | count) -%}
            '{{ ((states.sensor.tv_guide_abc.attributes.programSchedules | to_json(ensure_ascii=False)) | from_json())[i]['title'] | replace("'","\\'") }}'
            {%- if not loop.last %},{% endif -%}
            {% endfor -%} ]
          start_times: >-
            [ {%- for i in range(0,((states.sensor.tv_guide_abc.attributes.programSchedules | to_json(ensure_ascii=False)) | from_json()) | count) -%}
            {{ ((states.sensor.tv_guide_abc.attributes.programSchedules | to_json(ensure_ascii=False)) | from_json())[i]['startTime'] }}
            {%- if not loop.last %},{% endif -%}
            {% endfor -%} ]
          end_times: >-
            [ {%- for i in range(0,((states.sensor.tv_guide_abc.attributes.programSchedules | to_json(ensure_ascii=False)) | from_json()) | count) -%}
            {{ ((states.sensor.tv_guide_abc.attributes.programSchedules | to_json(ensure_ascii=False)) | from_json())[i]['endTime'] }}
            {%- if not loop.last %},{% endif -%}
            {% endfor -%} ]
  - sensor:
      - name: NBC Show Announcement
        unique_id: nbc-show-announcement
        state: >-
          {% for title in states.sensor.nbc_shows.attributes.titles %}
          {%- set good_start_time = states.sensor.nbc_shows.attributes.start_times[loop.index0] < as_timestamp(now().replace(hour=22, minute=0, second=0)) | round(0) %}
          {%- if 'dateline' in title | lower and good_start_time -%}
          {{ title }} is on NBC at {{ states.sensor.nbc_shows.attributes.start_times[loop.index0] | timestamp_custom("%-I:%M %p") }}.
          {%- if not loop.last -%}
          {{ ' ' }}
          {%- endif %}
          {%- endif -%}
          {% endfor -%}
  - sensor:
      - name: FOX Show Announcement
        unique_id: fox-show-announcement
        state: >-
          {% for title in states.sensor.fox_shows.attributes.titles %}
          {%- set good_start_time = states.sensor.fox_shows.attributes.start_times[loop.index0] < as_timestamp(now().replace(hour=22, minute=0, second=0)) | round(0) %}
          {%- if 'masterchef' in title | lower and good_start_time -%}
          {{ title }} is on FOX at {{ states.sensor.fox_shows.attributes.start_times[loop.index0] | timestamp_custom("%-I:%M %p") }}.
          {%- if not loop.last -%}
          {{ ' ' }}
          {%- endif %}
          {%- endif -%}
          {% endfor -%}
  - sensor:
      - name: PBS Create Show Announcement
        unique_id: pbs-create-show-announcement
        state: >-
          {% for title in states.sensor.pbs_create_shows.attributes.titles %}
          {%- set good_start_time = states.sensor.pbs_create_shows.attributes.start_times[loop.index0] < as_timestamp(now().replace(hour=22, minute=0, second=0)) | round(0) %}
          {%- if 'belton' in title | lower and good_start_time -%}
          {{ title }} is on PBS Create at {{ states.sensor.pbs_create_shows.attributes.start_times[loop.index0] | timestamp_custom("%-I:%M %p") }}.
          {%- if not loop.last -%}
          {{ ' ' }}
          {%- endif %}
          {%- endif -%}
          {% endfor -%}
  - sensor:
      - name: ABC Show Announcement
        unique_id: abc-show-announcement
        state: >-
          {% for title in states.sensor.abc_shows.attributes.titles %}
          {%- set good_start_time = states.sensor.abc_shows.attributes.start_times[loop.index0] < as_timestamp(now().replace(hour=22, minute=0, second=0)) | round(0) %}
          {%- if 'shark tank' in title | lower and good_start_time %}
          {{ title }} is on ABC at {{ states.sensor.abc_shows.attributes.start_times[loop.index0] | timestamp_custom("%-I:%M %p") }}.
          {%- if not loop.last -%}
          {{ ' ' }}
          {%- endif %}
          {%- endif -%}
          {% endfor -%}

I have never tried this for sensors, but maybe it works there too.

Here are the code for some lovelace cards:

type: markdown
title: HACS Addons
content: |-
  {%- if is_state('sensor.hacs','0') -%}
    <b><font color=green>No updates</font></b>
  {%- else -%}
    <table width=100%>
    {%- set hacs_updates = state_attr('sensor.hacs','repositories') -%}
    {%- for hacs_update in hacs_updates -%} 
      <tr><td><b><font color=red>{{[hacs_update][0]['display_name']}}</b></font></td><td>{{[hacs_update][0]['installed_version']}}</td><td>{{[hacs_update][0]['available_version']}}</td></tr>
    {%- endfor -%}
    </table>
  {%- endif -%}
type: markdown
title: Home Assistant Integrations
content: |-
  <table width=100%><tr><td><b>
  {%- set hacs_updates = states.update -%}
  {%- for hacs_update in hacs_updates -%}
    <tr><td><b>
    {%- if (hacs_update.state=='off') -%}
      <font color=green>
    {%- else -%}
      <font color=red>
    {%- endif -%}
    {{hacs_update.attributes.title}}</font></b></td><td>{{hacs_update.attributes.installed_version}}</td><td>
    {%- if (hacs_update.state=='off') -%}
      &nbsp;
    {%- else -%}
      {{hacs_update.attributes.latest_version}}
    {%- endif -%}
    </td></tr>
  {%- endfor -%}
  </table>
type: markdown
title: Philips Hue devices
content: >-
  <table width=100%><tr><td> {% if
  (state_attr('sensor.philips_hue_bridge_data','topic')['config']['swupdate2']['bridge']['state'])=='noupdates'
  %}
    <font color=green>
  {% else %}
    <font color="red">
  {% endif %} <b>Hue Bridge v2</b></font></td><td>
  {{(state_attr('sensor.philips_hue_bridge_data','topic')['config']['apiversion'])}}
  </td><td> {% if
  (state_attr('sensor.philips_hue_bridge_data','topic')['config']['swupdate']['updatestate'])!=
  0 %}
    {{(state_attr('sensor.philips_hue_bridge_data','topic')['config']['swupdate']['text']).replace("BSB002 - ","")}}
  {% else %}
    &nbsp;
  {% endif %} {%- set lights =
  (state_attr('sensor.philips_hue_bridge_data','topic'))['lights'] %} {%- for
  light in lights.items() %}
    <tr><td>
    {%- if (light.1.swupdate.state=='noupdates') %}
      <font color=green>
    {%- else %}
      <font color=red>
    {%- endif %}
    <b>{{light.1.name}}</b></font></td><td>{{light.1.swversion}}
    </td><td>&nbsp;</td></tr>
  {%- endfor %} </table>

There’s the concept of YAML anchors and aliases (example posted here) but I doubt it will help with your examples. There’s just enough of a difference in each one of your examples that makes them ineligible for straightforward substitution using anchors and aliases.

Jinja2 supports the concept of macros and they can be defined and used in a template. However, they can only be consumed where they are defined (i.e. the macro’s scope is limited to the YAML key where it’s defined and cannot be referenced in the template of another YAML key). In other words, Home Assistant doesn’t support global Jinja2 macros.

There’s also the YAML !include statement (and !secret), allowing you to reference text defined elsewhere, but once again it’s a verbatim substitution of the YAML key’s entire value.