REST - Nutrislice JSON Values

Hey I just drove through Bettendorf today, small world. You probably have already figured it out by now, but here is the fix you were looking for just in case:

Change:

{{  day.menu_items | selectattr("food.food_category","equalto","entree") | slice(2) | first | join('; ', attribute="food.name") }}<br/>

To:

 {{  day.menu_items | selectattr("food.name", 'defined') | slice(1) | first | join('; ', attribute="food.name") }}<br/>

The defined part is important because it will error if the value doesnā€™t exist. Also changing slice(2) to slice(1) gives all the results. Otherwise it was cutting off some menu items for me. I also went with food.name because at least for our school the food category is never used. I took your code and built on it. Here is what I am using:

List meals for entire week:

{% for day in state_attr('sensor.school_lunch', 'days') |
selectattr("menu_items") | selectattr("date", "greaterthan",
(now()-timedelta(hours=12)).strftime("%Y-%m-%d")) %}

{%- if day.date == now().strftime("%Y-%m-%d") -%}<b><u>TODAY</b></u>:{{" "}}

{%- elif day.date == (now()+timedelta(hours=24)).strftime("%Y-%m-%d")
-%}<b><u>TOMORROW</b></u>:{{" "}}{{"
"}}

{%- else -%}<b><u> {{- strptime(day.date, "%Y-%m-%d").strftime("%A").upper() -}}</b></u>:{{"
"}}

{%- endif -%}

{% for result in day.menu_items | selectattr("position", 'defined')  %}

{%- if result.text != "" -%}
<br><b><i>{{ result.text }}</b></i><br>
{%- endif -%}

{%- if result.food is not none -%}
{{ result.food.name }}<br>
{%- endif -%}

{% endfor %}

<br>

{% endfor %}

This method lists each item in order so that I could include the section titles as well (ex: alternate). It ends up looking like this:

Screenshot_9-9-2024_121926_localha.czerkacorp.com

I also created a grid card to show the lunch menu with pictures for the next two days. I have the screen real estate so mine is larger than some people may want. I set it to show today and tomorrow if it is before 8AM or to show the next two days if it is after 8AM. I also hide the whole thing on Saturdays:

square: false
type: grid
columns: 2
cards:
  - type: markdown
    content: |-
      <center>
      {% for day in state_attr('sensor.school_lunch', 'days') |
      selectattr("menu_items") | selectattr("date", "equalto",
      now().strftime("%Y-%m-%d")) %}

      <b><u>TODAY</b></u>


      {% for result in day.menu_items | selectattr("position", 'defined')  %}

      {%- if result.text != "" -%}
      <font color='yellow'><br><b><i>{{ result.text }}</b></i><br><br></font>
      {%- endif -%}

      {%- if result.food is not none -%}
      <img src='{{ result.food.image_url }}' width='150' ><br>
      {%- endif -%}

      {%- if result.food is not none -%}
      {{ result.food.name }}<br><br>
      {%- endif -%}

      {% endfor %}

      <br>

      {% endfor %}
      </center>
    visibility:
      - condition: state
        entity: binary_sensor.nutrislice_before_8
        state: 'on'
  - type: markdown
    content: |-
      <center>
      {% for day in state_attr('sensor.school_lunch', 'days') |
      selectattr("menu_items") | selectattr("date", "equalto",
      (now()+timedelta(hours=24)).strftime("%Y-%m-%d")) %}

      <b><u>TOMORROW</b></u>


      {% for result in day.menu_items | selectattr("position", 'defined')  %}

      {%- if result.text != "" -%}
      <font color='yellow'><br><b><i>{{ result.text }}</b></i><br><br></font>
      {%- endif -%}

      {%- if result.food is not none -%}
      <img src='{{ result.food.image_url }}' width='150' ><br>
      {%- endif -%}

      {%- if result.food is not none -%}
      {{ result.food.name }}<br><br>
      {%- endif -%}

      {% endfor %}

      <br>

      {% endfor %}
      </center>
  - type: markdown
    content: >+
      <center>

      {% for day in state_attr('sensor.school_lunch', 'days') |

      selectattr("menu_items") | selectattr("date", "equalto",

      (now()+timedelta(hours=48)).strftime("%Y-%m-%d")) %}


      <b><u> {{- strptime(day.date, "%Y-%m-%d").strftime("%A").upper()
      -}}</b></u>



      {% for result in day.menu_items | selectattr("position", 'defined')  %}


      {%- if result.text != "" -%}

      <font color='yellow'><br><b><i>{{ result.text }}</b></i><br><br></font>

      {%- endif -%}


      {%- if result.food is not none -%}

      <img src='{{ result.food.image_url }}' width='150' ><br>

      {%- endif -%}


      {%- if result.food is not none -%}

      {{ result.food.name }}<br><br>

      {%- endif -%}


      {% endfor %}


      <br>


      {% endfor %}

      </center>

    visibility:
      - condition: state
        entity: binary_sensor.nutrislice_before_8
        state: 'off'
title: School Lunch
visibility:
  - condition: state
    entity: sensor.day_of_the_week
    state_not: '6'

Iā€™m no pro so there may be a better way of doing this, but it worked for me. Thanks for sharing your part!

@AdmiralAckbar This is really helpful, thank you for sharing your work!

As someone who is just getting my fingers into this kind of thing I wonder if I could ask:

How would you change the following code (just copied/pasted and changed the sensor) so that it only returns items where "food_category" = "entree" and then ignoring the first two items because they are for breakfast.

type: markdown
content: >-
{% for day in state_attr('sensor.bcps_menu', 'days') | selectattr("menu_items") | selectattr("date", "greaterthan", (now()-timedelta(hours=12)).strftime("%Y-%m-%d")) %}

{%- if day.date == now().strftime("%Y-%m-%d") -%}<b><u>TODAY</b></u>:{{" "}}

{%- elif day.date == (now()+timedelta(hours=24)).strftime("%Y-%m-%d") -%}<b><u>TOMORROW</b></u>:{{" "}}{{" "}}

{%- else -%}<b><u> {{- strptime(day.date, "%Y-%m-%d").strftime("%A").upper() -}}</b></u>:{{" "}}

{%- endif -%}

{% for result in day.menu_items | selectattr("position", 'defined')  %}

{%- if result.text != "" -%}

<br><b><i>{{ result.text }}</b></i><br>

{%- endif -%}

{%- if result.food is not none -%}

{{ result.food.name }}<br>

{%- endif -%}

{% endfor %}

<br>

{% endfor %}

Iā€™ve tried splicing and joining and adding ifs and stuff but havenā€™t gotten anything to output yet.

1 Like

funny you ask this because i was wondering something very similar (excluding breakfast), and also for the same district! following

I think Iā€™ve figured out that just adding a selectattr("food_category", 'equalto', "entree") to the for loop wonā€™t work because food_category is further down the hierarchy under the ā€œfoodā€ record.

So ideally I think it would be: select attribute: days, greater than today | select attribute, menu_items | select attribute, food | select attribute, food_category, equal to entree. And then start the for the loop at item 3.

Just need to figure out how to convert that to working code.

Edit: Used ChatGPT to get to this point:

{% set filtered_days = state_attr('sensor.bcps_menu', 'days')
  | selectattr('date', '>', (now() - timedelta(hours=12)).strftime('%Y-%m-%d'))
%}

{% for day in filtered_days %}
    {%- if day.date == now().strftime("%Y-%m-%d") -%}
    <b><u>TODAY</b></u>:{{" "}}

    {%- elif day.date == (now() + timedelta(days=1)).strftime("%Y-%m-%d") -%}
    <b><u>TOMORROW</b></u>:{{" "}}{{"
    "}}

    {%- else -%}
    <b><u>{{- strptime(day.date, "%Y-%m-%d").strftime("%A").upper() -}}</b></u>:{{"
    "}}

    {%- endif -%}

    {% for result in day.menu_items 
      | selectattr('food', 'defined') 
      | selectattr('food', '!=', none)
      | selectattr('food.food_category', 'equalto', 'entree') %}
        
        {%- if result.text != "" -%}
        <br><b><i>{{ result.text }}</b></i><br>
        {%- endif -%}

        {%- if result.food is not none -%}
        {{ result.food.name }}<br>
        {%- endif -%}
    {% endfor %}

<br>
{% endfor %}

Which outputs:

TODAY: 
Assorted Savory Bread
Mini Waffles
Chicken Nuggets
Yogurt Entree, 8oz
Bento Box with Turkey & Cheese Pinwheels
Bento Box with Cheese


TOMORROW:
Assorted Muffin
Assorted Savory Bread
Cereal, Assorted
Pancake Wrapped Turkey Sausage
Hot Dog
Yogurt Entree, 8oz
Chef Salad
Bento Box with Tuna


FRIDAY:
Granola Round
Manager's Choice EntrƩe
Personal Pizza (Round)
Yogurt Entree, 8oz
Turkey & Ham Club Wrap
Mgr Choice Vegetarian Salad/Bento

Now trying to figure out how to skip the first two items, and maybe only keep items in position 1 and 2.

1 Like

Hopefully, Iā€™m not spamming this. Iā€™ve got this working more or less how I want it, though.

type: markdown
content: >-
  {% set filtered_days = state_attr('sensor.bcps_menu', 'days') |
  selectattr('date', '>', (now() - timedelta(hours=12)).strftime('%Y-%m-%d')) %}

  {% for day in filtered_days %}
  {% set day_of_week = strptime(day.date, "%Y-%m-%d").strftime("%A") %}

  {# Skip weekends (Saturday and Sunday) #}
  {% if day_of_week in ['Saturday', 'Sunday'] %}
    {% continue %}
  {% endif %}

  {%- if day.date == now().strftime("%Y-%m-%d") -%}
  <b><u>TODAY</b></u>:<br>{{" "}}

  {%- elif day.date == (now() + timedelta(days=1)).strftime("%Y-%m-%d") -%}
  <b><u>TOMORROW</b></u>:<br>{{" "}}{{"
  "}}

  {%- else -%}
  <b><u>{{- day_of_week.upper() -}}</b></u>:{{"
  "}}

  {%- endif -%}

  {# Counter for tracking the number of position 1 items #}
  {% set position_1_counter = 0 %}

  {% for result in day.menu_items 
    | selectattr('food', 'defined') 
    | selectattr('food', '!=', none)
    | selectattr('food.food_category', 'equalto', 'entree')
    | selectattr('position', 'in', [1, 2, 3, 4]) %}

    {%- if result.position == 1 %}
      {% set position_1_counter = position_1_counter + 1 %}
      {%- if position_1_counter == 2 %}
  
      {% endif %}
    {% endif %}

    {%- if result.text != "" -%}
    <b><i>{{ result.text }}</b></i>
    {%- endif -%}

    {%- if result.food is not none -%}
    {{ result.food.name }}
    {%- endif %}
  {% endfor %}

  {% endfor %}

Which returns:
image
Iā€™d like to have a line, or an icon or something where it has a break for the second ā€˜position = 1ā€™ but this code has that line break, but nothing I put in that space shows up in the cardā€¦not sure why.

I cannot test mine against a category because our district doesnā€™t use it, but try something like this to filter out the first two and entree only:

{% set ns = namespace(count=0) %}

{% for day in state_attr('sensor.bcps_menu', 'days') |
selectattr("menu_items") | selectattr("date", "greaterthan",
(now()-timedelta(hours=12)).strftime("%Y-%m-%d")) %}


{%- if day.date == now().strftime("%Y-%m-%d") -%}<b><u>TODAY</b></u>:{{" "}}

{%- elif day.date == (now()+timedelta(hours=24)).strftime("%Y-%m-%d")
-%}<b><u>TOMORROW</b></u>:{{" "}}{{"
"}}

{%- else -%}<b><u> {{- strptime(day.date, "%Y-%m-%d").strftime("%A").upper() -}}</b></u>:{{"
"}}

{%- endif -%}

  {% for result in day.menu_items | selectattr("position", 'defined')  %}

  {%- if result.text != "" -%}
  <font color='yellow'><br><b><i>{{ result.text }}</b></i><br><br></font>
  {%- endif -%}

  {%- if result.food is not none -%}
    {%- if 'Entree' in result.food.food_category -%}    
    {% set ns.count = ns.count + 1 %}
    {%- if ns.count > 2 -%}
      {{ result.food.name }}<br>
    {%- endif -%}
  {%- endif -%}
  
  {%- endif -%}

  {% endfor %}

  <br>

  {% endfor %}

my (our?) district occasionally has days with 3 breakfast entrees, though i think its fairly rare