3D printer Mushroom style card

Good morning,
I’ve been working on trying to add a mushroom style card to my dashboard for my Prusa MK4 printer. I came across an apparently abandoned add-on (threedy-card), designed for Octoprint connected printers. Octoprint is not recommended for use with the Prusa Mk4.

I’ve set up a basic card using mushroom entities, stack-in-cards, and horizontal-stacks, to resemble the threedy v2 card, and PrusaLink to link to my printer. I also have a conditional card showing time remaining when the printer is active. When it is idle, the conditional card is not there.

From threedy:

My current iteration:
image

A few things…

First, are there any other options that people are using other than Threedy? I want to use a Mushroom or Tile type card to keep that minimalistic appearance.

Second, if there aren’t any other options, can anyone provide me with any advice on how to format the temp sensors to appear more like the Threedy version. Specifically, with the horizontal stack, it’ll divide the card equally and fill in with white space. I’d rather have the temp values further to the left without the extra whtiespace. I’m also curious how I can change the icon when printing to show the printing percentage, like the Threedy version. The mushroom entity secondary info shoudl show printing and a numerical percentage, however, I’m not sure how one goes about changing the icon they way the Threedy add-on does.

Below is my current code.

type: custom:stack-in-card
mode: vertical
cards:
  - type: horizontal-stack
    cards:
      - type: custom:mushroom-entity-card
        entity: sensor.prusalink
        name: Prusa Mk4
        icon: mdi:printer-3d-nozzle
  - type: horizontal-stack
    cards:
      - type: custom:mushroom-entity-card
        style: |
          ha-card {
            border: none;
            align-items: left;
          }
        entity: sensor.prusalink_nozzle_temperature
        tap_action:
          action: none
        hold_action:
          action: none
        double_tap_action:
          action: none
        primary_info: none
        secondary_info: state
        icon: mdi:printer-3d-nozzle-heat
        icon_color: orange
      - type: custom:mushroom-entity-card
        style: |
          ha-card {
            border: none;
            align-items: left;
          }
        entity: sensor.prusalink_heatbed_temperature
        tap_action:
          action: none
        hold_action:
          action: none
        double_tap_action:
          action: none
        icon: mdi:heating-coil
        icon_color: orange
        primary_info: none
        fill_container: false
      - type: conditional
        conditions:
          - condition: state
            entity: sensor.prusalink_print_finish
            state_not: unavailable
        card:
          type: custom:mushroom-entity-card
          entity: sensor.prusalink_print_finish
          icon: mdi:alarm
          primary_info: none

I’ve also been researching how to create a threedy-style mushroom printer card and came across this post. To your question about temp sensors, you should look into using the mushroom chips card. The border progress bar is created using card-mod and templating. The percentage as part of the secondary info can also be done using templates.

I have been putting together a card. It uses mushroom cards, card-mod, and stack-in-card. I added a tap action to pull up my printer camera and hold action to go to a more detailed dashboard. I also added a chip to show the estimated time of completion.

Useful Links:
Card mod styling guide
Specific post creating threedy-like mushroom card - I would suggest reading through the whole thread for tips on creating animations.

type: custom:stack-in-card
cards:
  - type: custom:mushroom-template-card
    entity: camera.octoprint_camera
    primary: Prusa MK3S+
    secondary: |-
      {% if is_state('sensor.octoprint_print_status','Printing') %}
        {{ (states('sensor.octoprint_print_progress') | round(0) )}}% {{states('sensor.octoprint_print_status')}}
      {% else %}
        {{states('sensor.octoprint_print_status')}}
      {% endif %}       
    icon: mdi:printer-3d-nozzle
    icon_color: black
    tap_action:
      action: more-info
    hold_action:
      action: navigate
      navigation_path: /lovelace/3d-printer
    card_mod:
      style:
        mushroom-shape-icon$: |
          .shape {
            background: radial-gradient(var(--card-background-color) 60%, transparent 0%), conic-gradient(rgb(252,109,9) {{ states('sensor.octoprint_print_progress') | round(0) }}% 0%, var(--card-background-color) 0% 100%);
          }
          .shape:after {
            content: "";
            height: 100%;
            width: 100%;
            position: absolute;
            border-radius: 50%;
            background: rgba(var(--rgb-{{ config.icon_color }}), 0.1);
          }
        .: |
          ha-card {
            border: none;
          }
  - type: custom:mushroom-chips-card
    chips:
      - type: template
        content: >-
          {{ (((states('sensor.octoprint_actual_tool0_temp') | float - 32) * 5 /
          9) | round(1) )}} °C
        icon: mdi:printer-3d-nozzle-heat
        card_mod:
          style: |
            ha-card {
              --chip-background: rgba(var(--rgb-{{ config.icon_color }}), 0.1);
              border: none;
            }
      - type: template
        content: >-
          {{ (((states('sensor.octoprint_actual_bed_temp') | float - 32) * 5 /
          9) | round(1) )}} °C
        icon: mdi:heating-coil
        card_mod:
          style: |
            ha-card {
              --chip-background: rgba(var(--rgb-{{ config.icon_color }}), 0.1);
              border: none;
            }
      - type: conditional
        conditions:
          - condition: state
            entity: binary_sensor.octoprint_printing
            state: 'on'
        chip:
          type: template
          content: >-
            {{ states('sensor.octoprint_estimated_finish_time') | as_timestamp |
            timestamp_custom ('%H:%M') }}
          icon: mdi:timer-sand-complete
          card_mod:
            style: |
              ha-card {
                --chip-background: --chip-background: rgba(var(--rgb-{{ config.icon_color }}), 0.1);
                border: none;
              }
      - type: conditional
        conditions:
          - condition: state
            entity: binary_sensor.octoprint_printing
            state: 'on'
        chip:
          type: template
          content: >-
            {% set time = (states('sensor.octoprint_print_time') | int) | int %}
            {% set minutes = ((time % 3600) / 60) | int %} {% set hours = ((time
            % 86400) / 3600) | int %} {% set days = (time / 86400) | int %}

            {%- if time < 60 -%}
              Less than a minute
              {%- else -%}
              {%- if days > 0 -%}
                {{ days }}d
              {%- endif -%}
              {%- if hours > 0 -%}
                {%- if days > 0 -%}
                  {{ ' ' }}
                {%- endif -%}
                {{ hours }}h
              {%- endif -%}
              {%- if minutes > 0 -%}
                {%- if days > 0 or hours > 0 -%}
                  {{ ' ' }}
                {%- endif -%}
                {{ minutes }}m
              {%- endif -%}
            {%- endif -%}
          icon: mdi:timer
          card_mod:
            style: |
              ha-card {
                --chip-background: --chip-background: rgba(var(--rgb-{{ config.icon_color }}), 0.1);
              border: none;
              }
  - type: custom:mushroom-chips-card
    chips:
      - type: entity
        entity: button.octoprint_pause_job
        icon_color: white
        icon: mdi:pause
        content_info: none
        tap_action:
          action: toggle
        card_mod:
          style: |
            ha-card {
              --chip-background: rgba(var({{ '--rgb-grey' }}), 0.7);
              --icon-color: rgb(var(--rgb-white));
            } 
      - type: entity
        entity: button.octoprint_emergency_stop
        icon_color: white
        icon: mdi:alert-octagon
        content_info: none
        tap_action:
          action: toggle
        card_mod:
          style: |
            ha-card {
              --chip-background: rgba(var({{ '--rgb-red' }}), 1);
            } 
    card_mod:
      style: |
        ha-card {
            --chip-box-shadow: none;
            top: 16px;
            width: -webkit-fill-available;
            right: 12px;
            position: absolute;
        } 
        .chip-container {
            right: 0px;
            position: absolute;
        }

EDIT 1: 02 Jan 2024 My latest code revision as of
EDIT 2: 30 Jan 2024 Changed the Today/Tomorrow estimated finished time template, which wasn’t working for me using utcnow().

type: custom:stack-in-card
cards:
  - type: custom:mushroom-template-card
    entity: input_boolean.3d_printer_camera_view
    primary: Prusa MK3S+
    tap_action:
      action: toggle
    hold_action:
      action: navigate
      navigation_path: /lovelace/3d-printer
    secondary: |-
      {% if is_state('sensor.octoprint_print_status','Printing') or
      is_state('sensor.octoprint_print_status','Resuming') or
      is_state('sensor.octoprint_print_status','Pausing') or
      is_state('sensor.octoprint_print_status','Paused') %}
        {{ (states('sensor.octoprint_print_progress') | round(0) )}}% {{states('sensor.octoprint_print_status')}}
        {% set list = states('sensor.octoprint_print_file').split('_') %}
        {{list[list | length-3]}}
      {% else %}
        {{states('sensor.octoprint_print_status')}}
      {% endif %}       
    icon: >-
      {% if is_state('sensor.octoprint_print_status','Operational') %}
        mdi:printer-3d
      {% elif is_state('sensor.octoprint_print_status','Printing') or
      is_state('sensor.octoprint_print_status','Resuming') or
      is_state('sensor.octoprint_print_status','Pausing') or
      is_state('sensor.octoprint_print_status','Paused') %}
        mdi:printer-3d-nozzle
      {% elif is_state('sensor.octoprint_print_status','Cancelling') or
      is_state('sensor.octoprint_print_status','Error') or
      is_state('sensor.octoprint_print_status','Offline after error') %}
        mdi:close-octagon
      {% elif is_state('sensor.octoprint_print_status','unavailable') or
      is_state('sensor.octoprint_print_status','Unknown') %}
        mdi:printer-3d-off
      {% endif %}
    icon_color: >-
      {% if is_state('sensor.octoprint_print_status','Paused') or
      is_state('sensor.octoprint_print_status','Pausing') %}
        #fc6d09
      {% elif is_state('sensor.octoprint_print_status','Cancelling') or
      is_state('sensor.octoprint_print_status','Error') or
      is_state('sensor.octoprint_print_status','Offline after error') %}
        red
      {% else %}
        var(--primary-text-color)
      {% endif %}
    badge_icon: >-
      {% if is_state('sensor.octoprint_print_status','Paused') or
      is_state('sensor.octoprint_print_status','Pausing') %}
        mdi:pause
      {% elif is_state('sensor.octoprint_print_status','Resuming') %}
        mdi:play
      {% endif %}
    badge_color: >-
      {% if is_state('sensor.octoprint_print_status','Paused') or
      is_state('sensor.octoprint_print_status','Pausing') %}
        grey
      {% elif is_state('sensor.octoprint_print_status','Resuming') %}
        green
      {% endif %}
    card_mod:
      style:
        mushroom-shape-icon$: |
          .shape {
            {% if is_state('sensor.octoprint_print_status','Printing') or
            is_state('sensor.octoprint_print_status','Resuming') %}
              background: radial-gradient(var(--card-background-color) 60%, transparent 0%), conic-gradient(rgb(252,109,9) {{ states('sensor.octoprint_print_progress') | round(0) }}% 0%, var(--card-background-color) 0% 100%);
            {% elif is_state('sensor.octoprint_print_status','Operational') %}
              background: radial-gradient(var(--card-background-color) 60%, transparent 0%), conic-gradient(rgb(53,190,37) 100% 0%, var(--card-background-color) 0% 100%);              
            {% elif is_state('sensor.octoprint_print_status','Cancelling') or
            is_state('sensor.octoprint_print_status','Error') or
            is_state('sensor.octoprint_print_status','Offline after error')%}
              background: radial-gradient(var(--card-background-color) 60%, transparent 0%), conic-gradient(red 100% 0%, var(--card-background-color) 0% 100%);              
            {% else %}
              background: radial-gradient(var(--card-background-color) 60%, transparent 0%), conic-gradient(#9e9e9e {{ states('sensor.octoprint_print_progress') | round(0) }}% 0%, var(--card-background-color) 0% 100%);
            {% endif %} 
          }
          .shape:after {
            content: "";
            height: 100%;
            width: 100%;
            position: absolute;
            border-radius: 50%;
          }
        .: |
          ha-state-icon {
            {% if is_state('sensor.octoprint_print_status','Printing') or
            is_state('sensor.octoprint_print_status','Resuming')%}
              clip-path: inset(83% 72% 0 0);
            {% endif %}
          }
          ha-card {
            border: none;
          }
          mushroom-badge-icon {
            {% if is_state('sensor.octoprint_print_status','Pausing') or
            is_state('sensor.octoprint_print_status','Paused')%}
              animation: pulse 2s infinite;
            {% endif %}
          }
  - type: custom:mushroom-chips-card
    chips:
      - type: template
        content: >-
          {{ (((states('sensor.octoprint_actual_tool0_temp') | float - 32) * 5 /
          9) | round(1) )}} °C
        icon: mdi:printer-3d-nozzle-heat
        entity: sensor.octoprint_actual_tool0_temp
        tap_action:
          action: more-info
        hold_action:
          action: navigate
          navigation_path: /lovelace/3d-printer
        card_mod:
          style: |
            ha-card {
              border: none;
            }
      - type: template
        content: >-
          {{ (((states('sensor.octoprint_actual_bed_temp') | float - 32) * 5 /
          9) | round(1) )}} °C
        icon: mdi:heating-coil
        entity: sensor.octoprint_actual_bed_temp
        tap_action:
          action: more-info
        hold_action:
          action: navigate
          navigation_path: /lovelace/3d-printer
        card_mod:
          style: |
            ha-card {
              border: none;
            }
      - type: conditional
        conditions:
          - condition: state
            entity: binary_sensor.octoprint_printing
            state: 'on'
        chip:
          type: template
          content: >-
            {% set time = (states('sensor.octoprint_print_time') | int) | int %}
            {% set minutes = ((time % 3600) / 60) | int %} {% set hours = ((time
            % 86400) / 3600) | int %} {% set days = (time / 86400) | int %}

            {%- if time < 60 -%}
              Less than a minute
              {%- else -%}
              {%- if days > 0 -%}
                {{ days }}d
              {%- endif -%}
              {%- if hours > 0 -%}
                {%- if days > 0 -%}
                  {{ ' ' }}
                {%- endif -%}
                {{ hours }}h
              {%- endif -%}
              {%- if minutes > 0 -%}
                {%- if days > 0 or hours > 0 -%}
                  {{ ' ' }}
                {%- endif -%}
                {{ minutes }}m
              {%- endif -%}
            {%- endif -%}
          icon: mdi:timer-outline
          entity: sensor.octoprint_print_time
          tap_action:
            action: more-info
          hold_action:
            action: navigate
            navigation_path: /lovelace/3d-printer
          card_mod:
            style: |
              ha-card {
              border: none;
              }
      - type: conditional
        conditions:
          - condition: state
            entity: binary_sensor.octoprint_printing
            state: 'on'
        chip:
          type: template
          content: >
            {% if now().day ==
            as_timestamp(states('sensor.octoprint_estimated_finish_time')) |
            timestamp_custom('%d') | int %}
              Today {{as_timestamp(states('sensor.octoprint_estimated_finish_time')) | timestamp_custom ('%H:%M') }}
            {% elif now().day <
            as_timestamp(states('sensor.octoprint_estimated_finish_time')) |
            timestamp_custom('%d') | int %}
              Tmrw {{as_timestamp(states('sensor.octoprint_estimated_finish_time')) | timestamp_custom ('%H:%M') }}
            {% elif utcnow().day >
            as_timestamp(states('sensor.octoprint_estimated_finish_time')) |
            timestamp_custom('%d') | int %}
              Null
            {% else %} 
              {{as_timestamp(states('sensor.octoprint_estimated_finish_time')) | timestamp_custom ('%b %d %H:%M') }} 
            {% endif %}
          icon: mdi:clock-check-outline
          entity: sensor.octoprint_estimated_finish_time
          tap_action:
            action: more-info
          hold_action:
            action: navigate
            navigation_path: /lovelace/3d-printer
          card_mod:
            style: |
              ha-card {
                border: none;
              }
  - type: custom:mushroom-chips-card
    chips:
      - type: conditional
        conditions:
          - condition: or
            conditions:
              - condition: state
                entity: sensor.octoprint_print_status
                state: Printing
              - condition: state
                entity: sensor.octoprint_print_status
                state: Resuming
        chip:
          type: entity
          entity: button.octoprint_pause_job
          icon_color: white
          icon: mdi:pause
          content_info: none
          tap_action:
            action: toggle
          card_mod:
            style: |
              ha-card {
                --chip-background: rgba(var(--rgb-grey), 0.7);
                --icon-color: rgb(var(--rgb-white));
              } 
      - type: conditional
        conditions:
          - condition: or
            conditions:
              - condition: state
                entity: sensor.octoprint_print_status
                state: Paused
              - condition: state
                entity: sensor.octoprint_print_status
                state: Pausing
        chip:
          type: entity
          entity: button.octoprint_resume_job
          icon_color: white
          icon: mdi:play
          content_info: none
          tap_action:
            action: toggle
          card_mod:
            style: |
              ha-card {
                --chip-background: rgba(var(--rgb-green), 0.7);
                --icon-color: rgb(var(--rgb-white));
              } 
      - type: conditional
        conditions:
          - condition: or
            conditions:
              - condition: state
                entity: sensor.octoprint_print_status
                state: Printing
              - condition: state
                entity: sensor.octoprint_print_status
                state: Pausing
              - condition: state
                entity: sensor.octoprint_print_status
                state: Paused
              - condition: state
                entity: sensor.octoprint_print_status
                state: Resuming
        chip:
          type: entity
          entity: button.octoprint_emergency_stop
          icon_color: white
          icon: mdi:alert-octagon
          content_info: none
          tap_action:
            action: toggle
          card_mod:
            style: |
              ha-card {
                --chip-background: rgba(var(--rgb-red), 1);
              } 
    card_mod:
      style: |
        ha-card {
            --chip-box-shadow: none;
            top: 16px;
            width: -webkit-fill-available;
            right: 12px;
            position: absolute;
        } 
        .chip-container {
            right: 0px;
            position: absolute;
        }
  - type: conditional
    conditions:
      - condition: or
        conditions:
          - condition: state
            entity: sensor.octoprint_print_status
            state: Printing
          - condition: state
            entity: sensor.octoprint_print_status
            state: Resuming
    card:
      type: custom:mushroom-template-card
      icon: mdi:printer-3d-nozzle
      icon_color: var(--primary-text-color)
      entity: input_boolean.3d_printer_camera_view
      tap_action:
        action: toggle
      double_tap_action:
        action: call-service
        service: input_boolean.toggle
        target:
          entity_id: input_boolean.3d_printer_stl_preview
      hold_action:
        action: navigate
        navigation_path: /lovelace/3d-printer
      card_mod:
        style:
          mushroom-shape-icon$: |
            .shape {
              --shape-color: none;
            }
          .: |
            ha-card {
              position: absolute;
              top: 0px;
              border: none;
            }
            ha-state-icon {
              animation: print 1s linear infinite alternate;
            }
            @keyframes print {
              0% { transform: translateX(4px); }
              30% { clip-path: polygon(0 0, 100% 0%, 100% 100%, 0 100%, 0 26%); }
              100% { transform: translateX(-4px); clip-path: polygon(0 0, 100% 0%, 100% 100%, 40% 100%, 0 26%); }
            }
  - type: conditional
    conditions:
      - condition: state
        entity: input_boolean.3d_printer_camera_view
        state: 'on'
    card:
      type: custom:swipe-card
      reset_after: 5
      start_card: 1
      parameters:
        slidesPerView: 2
        preloadImages: true
        effect: flip
        pagination:
          type: bullets
      cards:
        - type: picture-entity
          entity: camera.octoprint_camera
          show_name: false
          show_state: false
          camera_view: live
          aspect_ratio: '4:3'
        - type: picture-entity
          entity: camera.slicer_preview
          show_state: false
          show_name: false
          aspect_ratio: '4:3'
card_mod:
  style: |
    ha-card {
      
    }

@gurubara ,
Looks like we are on a similar path. I’ve got mine pretty close to what you’ve got. I’ve only a few issues that I’m trying to work through, such as borders, but otherwise mine looks pretty much like yours. So minor differences, I’m not using Octoprint. I used it on my Ender 3, but I have a Mk4 and everything I’ve read says not to use Ocotoprint on it, so I’m using PrusaLink instead. I wasn’t using mushroom chip cards, I was using element cards, but that’s minor.

I had come across how to do the gradient print status using card-mod, although I fully admit I don’t understand how it works.

I still need to add a conditional element to mine, so the card isn’t visible if the printer is fully off, and I also need to add something if the filament runout sensor is tripped.

When it’s all done, I would love to know how to make it available for others to use, other than just posting the json code.

Thanks for sharing!

@gurubara

I applied the chip cards you used on yours, and I have to say it’s a better fit than what I have.

Original:

Chip cards:

A few issues that I’ll need to work out.

  1. The above screenshots were taken a minute or so apart. The temps are different.
    It looks like yours is converting from F to C. The PrusaLink temp is already in C, so the conversion isn’t necessary. That’s a quick fix.

  2. When printing, the end time doesn’t work. The PrusaLink add-on doesn’t have a print_time card like the OctoPrint card does. I may need to create a sensor that does the math between now and prusalink_print_finish, which should give the same result as yours does. I like the “less than a minute”, hours, days, etc, you have coded in.

One difference I have is that the pause / emergency stop buttons aren’t visible on unless it’s actually printing. Makes it a little less cluttered. Yours does the same thing for the print time chip cards.

Other than that, I was thinking of adding a print material chip card in this somewhere. I don’t know if OctoPrint has that sensor, but PrusaLink does.

1 Like

I got all the issues worked out. My main problem was getting the countdown timer to work. Working with time in templates when there are so many different formats presented with HA can a be a pain in the butt.

This is my end result while printing:

Screenshot 2023-12-15 at 8.12.08 AM

And at Idle:

The chip row is virtually identical to the one @gurubara created. I implemented a conditional card for the pause / resume chips, as well as the emergency stop, so they only show when those particular buttons are available. I also changed the Pause / Resume icon based upon the printing state (printing or paused), so it displays the appropriate icon, using two individual conditional cards. I’m sure there is a better/more elegant way to alt the icon based upon the print state, but it’s working for now.

type: custom:stack-in-card
mode: vertical
cards:
  - type: horizontal-stack
    style: |
      ha-card {
        border: none;
        border-width: 0px;
        border: 0px;
        align-items: left;
      }
    cards:
      - type: conditional
        conditions:
          - condition: state
            entity: sensor.prusalink_progress
            state_not: unavailable
        card:
          type: tile
          entity: sensor.prusalink_progress
          icon: mdi:printer-3d-nozzle
          color: blue
          name: Prusa MK4
          card_mod:
            style:
              ha-tile-icon$: |
                .shape {
                  background: radial-gradient(var(--card-background-color) 60%, transparent calc(60% + 1px)), conic-gradient(var(--tile-color) {{ (states(config.entity) |float ) }}% 0%, var(--card-background-color) 0% 100%);
                }
              .: |
                ha-card {
                  border: none;
                }
              ha-tile-info$: |
                .secondary {
                  visibility: hidden;
                }
                .secondary:before {
                  visibility: visible;
                  content: "{{ (states(config.entity) }}%";
                }   
      - type: conditional
        conditions:
          - condition: state
            entity: sensor.prusalink_progress
            state: unavailable
        card:
          type: tile
          style: |
            ha-card {
              width: 170px;
              border-width: 0px;
              border: 0px;
              border: none;
              align-items: left;
            }
          name: Prusa MK4
          entity: sensor.prusalink
          icon: mdi:printer-3d-nozzle
          color: blue
          show_entity_picture: false
  - type: custom:mushroom-chips-card
    chips:
      - type: template
        content: '{{ states(''sensor.prusalink_nozzle_temperature'') }} °C'
        icon: mdi:printer-3d-nozzle-heat
        card_mod:
          style: |
            ha-card {
              --chip-background: rgba(var(--rgb-{{ config.icon_color }}), 0.1);
              border: none;
            }
      - type: template
        content: '{{ states(''sensor.prusalink_heatbed_temperature'') }} °C'
        icon: mdi:heating-coil
        card_mod:
          style: |
            ha-card {
              --chip-background: rgba(var(--rgb-{{ config.icon_color }}), 0.1);
              border: none;
            }
      - type: conditional
        conditions:
          - condition: state
            entity: sensor.prusalink
            state: printing
        chip:
          type: template
          content: >-
            {{ states('sensor.prusalink_print_finish') | as_timestamp |
            timestamp_custom ('%H:%M') }}
          icon: mdi:timer-sand-complete
          card_mod:
            style: |
              ha-card {
                --chip-background: --chip-background: rgba(var(--rgb-{{ config.icon_color }}), 0.1);
                border: none;
              }
      - type: conditional
        conditions:
          - condition: state
            entity: sensor.prusalink
            state: printing
        chip:
          type: template
          content: >-
            {% set time =
            ((as_timestamp(states('sensor.prusalink_print_finish')) -
            as_timestamp(now())) | int) | int %} {% set minutes = ((time % 3600)
            / 60) | int %} {% set hours = ((time % 86400) / 3600) | int %} {%
            set days = (time / 86400) | int %}

            {%- if time < 60 -%}
              Less than a minute
              {%- else -%}
              {%- if days > 0 -%}
                {{ days }}d
              {%- endif -%}
              {%- if hours > 0 -%}
                {%- if days > 0 -%}
                  {{ ' ' }}
                {%- endif -%}
                {{ hours }}h
              {%- endif -%}
              {%- if minutes > 0 -%}
                {%- if days > 0 or hours > 0 -%}
                  {{ ' ' }}
                {%- endif -%}
                {{ minutes }}m
              {%- endif -%}
            {%- endif -%}
          icon: mdi:timer
          card_mod:
            style: |
              ha-card {
                --chip-background: --chip-background: rgba(var(--rgb-{{ config.icon_color }}), 0.1);
              border: none;
              }
  - type: custom:mushroom-chips-card
    chips:
      - type: conditional
        conditions:
          - condition: state
            entity: sensor.prusalink
            state: paused
        chip:
          type: entity
          entity: button.prusalink_resume_job
          icon_color: white
          icon: mdi:play
          content_info: none
          tap_action:
            action: toggle
          card_mod:
            style: |
              ha-card {
                --chip-background: rgba(var({{ '--rgb-grey' }}), 0.7);
                --icon-color: rgb(var(--rgb-white));
              }
      - type: conditional
        conditions:
          - condition: state
            entity: sensor.prusalink
            state: printing
        chip:
          type: entity
          entity: button.prusalink_resume_job
          icon_color: white
          icon: mdi:pause
          content_info: none
          tap_action:
            action: toggle
          card_mod:
            style: |
              ha-card {
                --chip-background: rgba(var({{ '--rgb-grey' }}), 0.7);
                --icon-color: rgb(var(--rgb-white));
              }
      - type: conditional
        conditions:
          - condition: state
            entity: button.prusalink_cancel_job
            state_not: unavailable
        chip:
          type: entity
          entity: button.prusalink_cancel_job
          icon_color: white
          icon: mdi:alert-octagon
          content_info: none
          tap_action:
            action: toggle
          card_mod:
            style: |
              ha-card {
                --chip-background: rgba(var({{ '--rgb-red' }}), 1);
              } 
    card_mod:
      style: |
        ha-card {
            --chip-box-shadow: none;
            top: 16px;
            width: -webkit-fill-available;
            right: 12px;
            position: absolute;
        } 
        .chip-container {
            right: 0px;
            position: absolute;
        }

I’m glad a that I figured out the time formatting. To make the print finish time available, I kept having to print the Prusa keychains so I had that valuable available to me for 9 minutes at a time :slight_smile:

Two remaining this to do. I want the card only to be visible when the printer is actually powered on (wrap the whole thing in a conditional card), and I need to add a material chip card to it, or perhaps add it on the primary element, maybe next to the percentage. I just need to play around with it and see how it all looks.

Sorry I didn’t mention the temperature conversion. The rest of my HA uses F and at the minute I was working on this card I didn’t feel like creating a template sensor, although I probably should so that I can use the sensor both in this card and in other dashboards.

Similar to you, I have been playing around with changing the icon depending on the state and adding badges for additional detail. I opted to use if/else statements in template cards for each config var, but I do not know if this is an efficient method either. I updated the pause/resume chip to a) change icon depending on if paused/printing, b) hide the chips with conditionals like you and c) fix the chip so tapping resume also works. In the pictures below, ignore the fact that there is no estimate finished time. I was using dev tools to set the sensor state instead of printing something.

type: custom:stack-in-card
cards:
  - type: custom:mushroom-template-card
    entity: camera.octoprint_camera
    primary: Prusa MK3S+
    secondary: |-
      {% if is_state('sensor.octoprint_print_status','Printing') or
      is_state('sensor.octoprint_print_status','Resuming') or
      is_state('sensor.octoprint_print_status','Pausing') or
      is_state('sensor.octoprint_print_status','Paused') %}
        {{ (states('sensor.octoprint_print_progress') | round(0) )}}% {{states('sensor.octoprint_print_status')}}
      {% else %}
        {{states('sensor.octoprint_print_status')}}
      {% endif %}       
    icon: >-
      {% if is_state('sensor.octoprint_print_status','Operational') %}
        mdi:printer-3d
      {% elif is_state('sensor.octoprint_print_status','Printing') or
      is_state('sensor.octoprint_print_status','Resuming') or
      is_state('sensor.octoprint_print_status','Pausing') or
      is_state('sensor.octoprint_print_status','Paused') %}
        mdi:printer-3d-nozzle
      {% elif is_state('sensor.octoprint_print_status','Cancelling') or
      is_state('sensor.octoprint_print_status','Error') %}
        mdi:close-octagon
      {% elif is_state('sensor.octoprint_print_status','Unavailable') or
      is_state('sensor.octoprint_print_status','Unknown') %}
        mdi:printer-3d-off
      {% endif %}
    icon_color: >-
      {% if is_state('sensor.octoprint_print_status','Paused') or
      is_state('sensor.octoprint_print_status','Pausing') %}
        #fc6d09
            {% elif is_state('sensor.octoprint_print_status','Cancelling') or
      is_state('sensor.octoprint_print_status','Error') %}
        red
      {% endif %}
    badge_icon: >-
      {% if is_state('sensor.octoprint_print_status','Paused') or
      is_state('sensor.octoprint_print_status','Pausing') %}
        mdi:pause
      {% elif is_state('sensor.octoprint_print_status','Resuming') %}
        mdi:play
      {% endif %}
    badge_color: >-
      {% if is_state('sensor.octoprint_print_status','Paused') or
      is_state('sensor.octoprint_print_status','Pausing') %}
        grey
      {% elif is_state('sensor.octoprint_print_status','Resuming') %}
        green
      {% endif %}
    tap_action:
      action: more-info
    hold_action:
      action: navigate
      navigation_path: /lovelace/3d-printer
    card_mod:
      style:
        mushroom-shape-icon$: |
          .shape {
            background: radial-gradient(var(--card-background-color) 60%, transparent 0%), conic-gradient(
            {% if is_state('sensor.octoprint_print_status','Printing') or
            is_state('sensor.octoprint_print_status','Resuming') %}
              rgb(252,109,9)
            {% elif is_state('sensor.octoprint_print_status','Operational') %}
              rgb(53,190,37)
            {% elif is_state('sensor.octoprint_print_status','Cancelling') or
            is_state('sensor.octoprint_print_status','Error') %}
              red
            {% else %}
              rgb(128,128,128)
            {% endif %} 
            {{ states('sensor.octoprint_print_progress') | round(0) }}% 0%, var(--card-background-color) 0% 100%);
          }
          .shape:after {
            content: "";
            height: 100%;
            width: 100%;
            position: absolute;
            border-radius: 50%;
            background: rgba(var(--rgb-{{ config.icon_color }}), 0.1);
          }
        .: |
          ha-card {
            border: none;
          }
  - type: custom:mushroom-chips-card
    chips:
      - type: template
        content: >-
          {{ (((states('sensor.octoprint_actual_tool0_temp') | float - 32) * 5 /
          9) | round(1) )}} °C
        icon: mdi:printer-3d-nozzle-heat
        card_mod:
          style: |
            ha-card {
              --chip-background: rgba(var(--rgb-{{ config.icon_color }}), 0.1);
              border: none;
            }
      - type: template
        content: >-
          {{ (((states('sensor.octoprint_actual_bed_temp') | float - 32) * 5 /
          9) | round(1) )}} °C
        icon: mdi:heating-coil
        card_mod:
          style: |
            ha-card {
              --chip-background: rgba(var(--rgb-{{ config.icon_color }}), 0.1);
              border: none;
            }
      - type: conditional
        conditions:
          - condition: state
            entity: binary_sensor.octoprint_printing
            state: 'on'
        chip:
          type: template
          content: >-
            {% set time = (states('sensor.octoprint_print_time') | int) | int %}
            {% set minutes = ((time % 3600) / 60) | int %} {% set hours = ((time
            % 86400) / 3600) | int %} {% set days = (time / 86400) | int %}

            {%- if time < 60 -%}
              Less than a minute
              {%- else -%}
              {%- if days > 0 -%}
                {{ days }}d
              {%- endif -%}
              {%- if hours > 0 -%}
                {%- if days > 0 -%}
                  {{ ' ' }}
                {%- endif -%}
                {{ hours }}h
              {%- endif -%}
              {%- if minutes > 0 -%}
                {%- if days > 0 or hours > 0 -%}
                  {{ ' ' }}
                {%- endif -%}
                {{ minutes }}m
              {%- endif -%}
            {%- endif -%}
          icon: mdi:timer-outline
          card_mod:
            style: |
              ha-card {
                --chip-background: --chip-background: rgba(var(--rgb-{{ config.icon_color }}), 0.1);
              border: none;
              }
      - type: conditional
        conditions:
          - condition: state
            entity: binary_sensor.octoprint_printing
            state: 'on'
        chip:
          type: template
          content: >-
            {{ states('sensor.octoprint_estimated_finish_time') | as_timestamp |
            timestamp_custom ('%H:%M') }}
          icon: mdi:clock-check-outline
          card_mod:
            style: |
              ha-card {
                --chip-background: --chip-background: rgba(var(--rgb-{{ config.icon_color }}), 0.1);
                border: none;
              }
  - type: custom:mushroom-chips-card
    chips:
      - type: conditional
        conditions:
          - condition: or
            conditions:
              - condition: state
                entity: sensor.octoprint_print_status
                state: Printing
              - condition: state
                entity: sensor.octoprint_print_status
                state: Resuming
        chip:
          type: entity
          entity: button.octoprint_pause_job
          icon_color: white
          icon: mdi:pause
          content_info: none
          tap_action:
            action: toggle
          card_mod:
            style: |
              ha-card {
                --chip-background: rgba(var({{ '--rgb-grey' }}), 0.7);
                --icon-color: rgb(var(--rgb-white));
              } 
      - type: conditional
        conditions:
          - condition: or
            conditions:
              - condition: state
                entity: sensor.octoprint_print_status
                state: Paused
              - condition: state
                entity: sensor.octoprint_print_status
                state: Pausing
        chip:
          type: entity
          entity: button.octoprint_resume_job
          icon_color: white
          icon: mdi:play
          content_info: none
          tap_action:
            action: toggle
          card_mod:
            style: |
              ha-card {
                --chip-background: rgba(var({{ '--rgb-green' }}), 0.7);
                --icon-color: rgb(var(--rgb-white));
              } 
      - type: conditional
        conditions:
          - condition: or
            conditions:
              - condition: state
                entity: sensor.octoprint_print_status
                state: Printing
              - condition: state
                entity: sensor.octoprint_print_status
                state: Pausing
              - condition: state
                entity: sensor.octoprint_print_status
                state: Paused
              - condition: state
                entity: sensor.octoprint_print_status
                state: Resuming
        chip:
          type: entity
          entity: button.octoprint_emergency_stop
          icon_color: white
          icon: mdi:alert-octagon
          content_info: none
          tap_action:
            action: toggle
          card_mod:
            style: |
              ha-card {
                --chip-background: rgba(var({{ '--rgb-red' }}), 1);
              } 
    card_mod:
      style: |
        ha-card {
            --chip-box-shadow: none;
            top: 16px;
            width: -webkit-fill-available;
            right: 12px;
            position: absolute;
        } 
        .chip-container {
            right: 0px;
            position: absolute;
        }
card_mod:
  style: |
    ha-card {

    }

I’m pretty happy with my results but may tweak colors. The other thing I might change are:

  1. How I template the ETA, by adding “Today/Tomorrow” or a date after the time so it is less confusing next to the elapsed time chip.

  2. I have a separate card that pulls the slicer picture from the 3mf file. If I can find a clean way to pull this up, I may add it in as a popup.

    type: markdown
    content: >-
      <img
      src="http://ip.address/plugin/prusaslicerthumbnails/thumbnail/{{states('sensor.octoprint_print_file')|regex_replace(find='gcode',
      replace='png', ignorecase=True)}}">
  1. Animations? Seems extra…

Octoprint unfortunately doesn’t support a filament type sensor, which would be cool. I’m interested to see how you implement it in case I ever switch to a printer that does support it!

1 Like

After a cup of coffee, I realized I can bootleg a filament sensor because prusaslicer exports the filament type in my print file name. Octoprint MQTT has a sensor for the print file name, which I’m also using to generate the url of the 3mf image mentioned in my previous post.

e.g. end_0.3mm_PLA_MK3S_14m.gcode will return “PLA” in the following template:

{% set list = states('sensor.octoprint_print_file').split('_') %}
{{list[list | length-3]}}

I just tacked it on to the end of the secondary info for now, would love to see what you implement.

Updated my ETA chip to specify which day the print will finish using the following chip card with new time template:

  - type: conditional
    conditions:
      - condition: state
        entity: binary_sensor.octoprint_printing
        state: 'on'
    chip:
      type: template
      content: >-
        {% if now().day == as_datetime(states('sensor.octoprint_estimated_finish_time')).day%}
        Today {{ as_timestamp(states('sensor.octoprint_estimated_finish_time')) | timestamp_custom ('%H:%M') }}
        {% elif now().day == as_datetime(states('sensor.octoprint_estimated_finish_time')).day - 1 %}
        Tmrw {{ as_timestamp(states('sensor.octoprint_estimated_finish_time')) | timestamp_custom ('%H:%M') }}
        {% elif now().day > as_datetime(states('sensor.octoprint_estimated_finish_time')).day%}

        {% else %}
        {{ as_timestamp(states('sensor.octoprint_estimated_finish_time')) | timestamp_custom ('%b %d %H:%M') }}
        {% endif%}
      icon: mdi:clock-check-outline
      card_mod:
        style: |
          ha-card {
            --chip-background: --chip-background: rgba(var(--rgb-{{ config.icon_color }}), 0.1);
            border: none;
          }

I’m really impressed with what you’ve managed to come up with. I’ve been studying what you’ve done, and what I can convert over to use the Prusalink sensors. Much of the changes I can effect with minor modification (the icon and badges, for instance). sensor.prusalink does not have an “operational” attribute option, but an “idle” attribute, so that is a minor difference. I believe it’s the same, non-running but ready to print state of the printer.

It also does not have a “resuming” option. I’m assuming would go straight from paused to printing. There is however the resume_job button, so the functionality is still there. Perhaps I can make some sort of helper to initiate after the resume button is pressed, but the sensor still shows as paused, to generate a “resuming” attribute on the card until the actual attribute changes to printing. That would give me a visual queue to let me know that the heat bed or nozzle are heating back up, or the extruding is moving to it’s prior print position, as opposed to thinking it’s not doing anything while it’s actually getting ready to resume printing.

I may need to start printing some more keychains to see if I can get the .day attribute from the sensor.prusalink_print_finish state. Even better, if I could figure out how to use developer tools to set that timestamp value, I can work with it templating. It was a little different for the time remaining chip than yours, so I’ll need to see how it actually interacts while printing.

Edit:

I figured out how to temporarily set the value of the timestamp (like 10 seconds). The timestamp from seems to work in the template. I’ll need to test later to verify the real life results.

I think the one remaining thing I want to add is some sort of notification for filament runout. PrusaLink doesn’t have a direct sensor value for filament runout, however, I was able to set up a push notification to my phone if the state of prusalink is printing, but the prusalink_material changes to “-----”

I’m sure I can do something similar on the mushroom card, but I’m unsure how I want to present it. I’m thinking of replacing the secondary information with some sort of notification (‘Change filament’ or ‘Filament out’). Since you’re having to pull the filament type from the print file name, this probably won’t do you any good. Does Octoprint have a sensor state for filament runout?

@gurubara

Is that conic-gradient working properly for you? I know you have the six screenshots showing the various states, but I don’t see the closing parenthesis, and all I’ve got is a grey icon circle with the printer-3d mdi icon. I’m not getting that outer gradient like you are showing when idle / operational. I’ve tried pulling out the If/elif logic and just throwing the rgb code in with a close parenthesis afterwards, and I’m still getting the same end result.

It just seems like something is missing.

I verified the sensor state in the dev tools, so the if statement isn’t the problem.

image

    card_mod:
      style:
        mushroom-shape-icon$: |
          .shape {
            background: radial-gradient(var(--card-background-color) 60%, transparent 0%), conic-gradient(
            {% if is_state('sensor.prusalink','Printing') 
              rgb(252,109,9)
            {% elif is_state('sensor.prusalink','idle') %}
              rgb(53,190,37)
            {% elif is_state('sensor.prusalink','cancelling') or is_state('sensor.prusalink','Error') %}
              red
            {% else %}
              rgb(128,128,128)
            {% endif %} 
            {{ states('sensor.prusalink_progress') | round(0) }}% 0%, var(--card-background-color) 0% 100%);
          }
          .shape:after {
            content: "";
            height: 100%;
            width: 100%;
            position: absolute;
            border-radius: 50%;
            background: rgba(var(--rgb-{{ config.icon_color }}), 0.1);
          }
        .: |
          ha-card {
            border: none;
          }

@tamorgen, it looks like you may have dropped a %} at the end of the if statement when removing the ‘or’ line below. Try:

            {% if is_state('sensor.prusalink','Printing') %}

For reference, the end of the parenthesis for the conic-gradient is at the end of the line below, right before the semicolon:

{{ states('sensor.octoprint_print_progress') | round(0) }}% 0%, var(--card-background-color) 0% 100%);

I’m enjoying making this card and kept adding to it. I added some icon animations for printing and paused states. I also embedded the camera and slicer images in the card using swipe-card. It is hidden by default and opens on tap action. I use an input_boolean helper as a toggle for the conditional card. swipe-card may not be supported anymore? I was having trouble setting certain parameters.

Also for the slicer image, I changed to using a camera entity instead of a markdown card because I was having trouble with the image loading on my mobile devices while not connected to my home Wi-Fi. A different option for this image may be to set an automation to save a local, temporary snapshot when a print starts, which could then be displayed in the markdown.

As for the resuming state, I haven’t played around enough to tell how useful it is. On a normal pause, it only flashes for a second, see the gif below. I haven’t played with a cold pause yet to see if it holds that state while reheating. Similarly, I haven’t looked at the cancelling state. I think the pausing, resuming, and cancelling states might be active when the printer is running relevant gcode scripts.

Octoprint MQTT integration in HA doesn’t have a preset filament sensor, but Octoprint MQTT does apparently push events for gcode changes. I was going to search around this afternoon or listen to it to the MQTT events and see if I can tell when specific print errors occur. e.g. look for M600 command, which is a filament change.

type: custom:stack-in-card
cards:
  - type: custom:mushroom-template-card
    entity: input_boolean.3d_printer_camera_view
    primary: Prusa MK3S+
    tap_action:
      action: toggle
    hold_action:
      action: navigate
      navigation_path: /lovelace/3d-printer
    secondary: |-
      {% if is_state('sensor.octoprint_print_status','Printing') or
      is_state('sensor.octoprint_print_status','Resuming') or
      is_state('sensor.octoprint_print_status','Pausing') or
      is_state('sensor.octoprint_print_status','Paused') %}
        {{ (states('sensor.octoprint_print_progress') | round(0) )}}% {{states('sensor.octoprint_print_status')}}
        {% set list = states('sensor.octoprint_print_file').split('_') %}
        {{list[list | length-3]}}
      {% else %}
        {{states('sensor.octoprint_print_status')}}
      {% endif %}       
    icon: >-
      {% if is_state('sensor.octoprint_print_status','Operational') %}
        mdi:printer-3d
      {% elif is_state('sensor.octoprint_print_status','Printing') or
      is_state('sensor.octoprint_print_status','Resuming') or
      is_state('sensor.octoprint_print_status','Pausing') or
      is_state('sensor.octoprint_print_status','Paused') %}
        mdi:printer-3d-nozzle
      {% elif is_state('sensor.octoprint_print_status','Cancelling') or
      is_state('sensor.octoprint_print_status','Error') %}
        mdi:close-octagon
      {% elif is_state('sensor.octoprint_print_status','Unavailable') or
      is_state('sensor.octoprint_print_status','Unknown') %}
        mdi:printer-3d-off
      {% endif %}
    icon_color: >-
      {% if is_state('sensor.octoprint_print_status','Paused') or
      is_state('sensor.octoprint_print_status','Pausing') %}
        #fc6d09
      {% elif is_state('sensor.octoprint_print_status','Cancelling') or
      is_state('sensor.octoprint_print_status','Error') %}
        red
      {% endif %}
    badge_icon: >-
      {% if is_state('sensor.octoprint_print_status','Paused') or
      is_state('sensor.octoprint_print_status','Pausing') %}
        mdi:pause
      {% elif is_state('sensor.octoprint_print_status','Resuming') %}
        mdi:play
      {% endif %}
    badge_color: >-
      {% if is_state('sensor.octoprint_print_status','Paused') or
      is_state('sensor.octoprint_print_status','Pausing') %}
        grey
      {% elif is_state('sensor.octoprint_print_status','Resuming') %}
        green
      {% endif %}
    card_mod:
      style:
        mushroom-shape-icon$: |
          .shape {
            {% if is_state('sensor.octoprint_print_status','Printing') or
            is_state('sensor.octoprint_print_status','Resuming') %}
              background: radial-gradient(var(--card-background-color) 60%, transparent 0%), conic-gradient(rgb(252,109,9) {{ states('sensor.octoprint_print_progress') | round(0) }}% 0%, var(--card-background-color) 0% 100%);
            {% elif is_state('sensor.octoprint_print_status','Operational') %}
              background: radial-gradient(var(--card-background-color) 60%, transparent 0%), conic-gradient(rgb(53,190,37) 100% 0%, var(--card-background-color) 0% 100%);              
            {% elif is_state('sensor.octoprint_print_status','Cancelling') or
            is_state('sensor.octoprint_print_status','Error') or
            is_state('sensor.octoprint_print_status','Offline after error')%}
              background: radial-gradient(var(--card-background-color) 60%, transparent 0%), conic-gradient(red 100% 0%, var(--card-background-color) 0% 100%);              
            {% else %}
              background: radial-gradient(var(--card-background-color) 60%, transparent 0%), conic-gradient(#9e9e9e {{ states('sensor.octoprint_print_progress') | round(0) }}% 0%, var(--card-background-color) 0% 100%);
            {% endif %} 
          }
          .shape:after {
            content: "";
            height: 100%;
            width: 100%;
            position: absolute;
            border-radius: 50%;
            background: rgba(var(--rgb-{{ config.icon_color }}), 0.1);
          }
        .: |
          ha-state-icon {
            {% if is_state('sensor.octoprint_print_status','Printing') or
            is_state('sensor.octoprint_print_status','Resuming')%}
              clip-path: inset(83% 72% 0 0);
            {% endif %}
          }
          ha-card {
            border: none;
          }
          mushroom-badge-icon {
            {% if is_state('sensor.octoprint_print_status','Pausing') or
            is_state('sensor.octoprint_print_status','Paused')%}
              animation: pulse 2s infinite;
            {% endif %}
          }
  - type: custom:mushroom-chips-card
    chips:
      - type: template
        content: >-
          {{ (((states('sensor.octoprint_actual_tool0_temp') | float - 32) * 5 /
          9) | round(1) )}} °C
        icon: mdi:printer-3d-nozzle-heat
        entity: sensor.octoprint_actual_tool0_temp
        tap_action:
          action: more-info
        hold_action:
          action: navigate
          navigation_path: /lovelace/3d-printer
        card_mod:
          style: |
            ha-card {
              --chip-background: rgba(var(--rgb-{{ config.icon_color }}), 0.1);
              border: none;
            }
      - type: template
        content: >-
          {{ (((states('sensor.octoprint_actual_bed_temp') | float - 32) * 5 /
          9) | round(1) )}} °C
        icon: mdi:heating-coil
        entity: sensor.octoprint_actual_bed_temp
        tap_action:
          action: more-info
        hold_action:
          action: navigate
          navigation_path: /lovelace/3d-printer
        card_mod:
          style: |
            ha-card {
              --chip-background: rgba(var(--rgb-{{ config.icon_color }}), 0.1);
              border: none;
            }
      - type: conditional
        conditions:
          - condition: state
            entity: binary_sensor.octoprint_printing
            state: 'on'
        chip:
          type: template
          content: >-
            {% set time = (states('sensor.octoprint_print_time') | int) | int %}
            {% set minutes = ((time % 3600) / 60) | int %} {% set hours = ((time
            % 86400) / 3600) | int %} {% set days = (time / 86400) | int %}

            {%- if time < 60 -%}
              Less than a minute
              {%- else -%}
              {%- if days > 0 -%}
                {{ days }}d
              {%- endif -%}
              {%- if hours > 0 -%}
                {%- if days > 0 -%}
                  {{ ' ' }}
                {%- endif -%}
                {{ hours }}h
              {%- endif -%}
              {%- if minutes > 0 -%}
                {%- if days > 0 or hours > 0 -%}
                  {{ ' ' }}
                {%- endif -%}
                {{ minutes }}m
              {%- endif -%}
            {%- endif -%}
          icon: mdi:timer-outline
          entity: sensor.octoprint_print_time
          tap_action:
            action: more-info
          hold_action:
            action: navigate
            navigation_path: /lovelace/3d-printer
          card_mod:
            style: |
              ha-card {
                --chip-background: --chip-background: rgba(var(--rgb-{{ config.icon_color }}), 0.1);
              border: none;
              }
      - type: conditional
        conditions:
          - condition: state
            entity: binary_sensor.octoprint_printing
            state: 'on'
        chip:
          type: template
          content: >-
            {% if utcnow().day ==
            as_datetime(states('sensor.octoprint_estimated_finish_time')).day%}
            Today {{
            as_timestamp(states('sensor.octoprint_estimated_finish_time')) |
            timestamp_custom ('%H:%M') }} {% elif utcnow().day ==
            as_datetime(states('sensor.octoprint_estimated_finish_time')).day -
            1 %} Tmrw {{
            as_timestamp(states('sensor.octoprint_estimated_finish_time')) |
            timestamp_custom ('%H:%M') }} {% elif utcnow().day >
            as_datetime(states('sensor.octoprint_estimated_finish_time')).day%}

            {% else %} {{
            as_timestamp(states('sensor.octoprint_estimated_finish_time')) |
            timestamp_custom ('%b %d %H:%M') }} {% endif%}
          icon: mdi:clock-check-outline
          entity: sensor.octoprint_estimated_finish_time
          tap_action:
            action: more-info
          hold_action:
            action: navigate
            navigation_path: /lovelace/3d-printer
          card_mod:
            style: |
              ha-card {
                --chip-background: --chip-background: rgba(var(--rgb-{{ config.icon_color }}), 0.1);
                border: none;
              }
  - type: custom:mushroom-chips-card
    chips:
      - type: conditional
        conditions:
          - condition: or
            conditions:
              - condition: state
                entity: sensor.octoprint_print_status
                state: Printing
              - condition: state
                entity: sensor.octoprint_print_status
                state: Resuming
        chip:
          type: entity
          entity: button.octoprint_pause_job
          icon_color: white
          icon: mdi:pause
          content_info: none
          tap_action:
            action: toggle
          card_mod:
            style: |
              ha-card {
                --chip-background: rgba(var({{ '--rgb-grey' }}), 0.7);
                --icon-color: rgb(var(--rgb-white));
              } 
      - type: conditional
        conditions:
          - condition: or
            conditions:
              - condition: state
                entity: sensor.octoprint_print_status
                state: Paused
              - condition: state
                entity: sensor.octoprint_print_status
                state: Pausing
        chip:
          type: entity
          entity: button.octoprint_resume_job
          icon_color: white
          icon: mdi:play
          content_info: none
          tap_action:
            action: toggle
          card_mod:
            style: |
              ha-card {
                --chip-background: rgba(var({{ '--rgb-green' }}), 0.7);
                --icon-color: rgb(var(--rgb-white));
              } 
      - type: conditional
        conditions:
          - condition: or
            conditions:
              - condition: state
                entity: sensor.octoprint_print_status
                state: Printing
              - condition: state
                entity: sensor.octoprint_print_status
                state: Pausing
              - condition: state
                entity: sensor.octoprint_print_status
                state: Paused
              - condition: state
                entity: sensor.octoprint_print_status
                state: Resuming
        chip:
          type: entity
          entity: button.octoprint_emergency_stop
          icon_color: white
          icon: mdi:alert-octagon
          content_info: none
          tap_action:
            action: toggle
          card_mod:
            style: |
              ha-card {
                --chip-background: rgba(var({{ '--rgb-red' }}), 1);
              } 
    card_mod:
      style: |
        ha-card {
            --chip-box-shadow: none;
            top: 16px;
            width: -webkit-fill-available;
            right: 12px;
            position: absolute;
        } 
        .chip-container {
            right: 0px;
            position: absolute;
        }
  - type: conditional
    conditions:
      - condition: or
        conditions:
          - condition: state
            entity: sensor.octoprint_print_status
            state: Printing
          - condition: state
            entity: sensor.octoprint_print_status
            state: Resuming
    card:
      type: custom:mushroom-template-card
      icon: mdi:printer-3d-nozzle
      icon_color: var(--rgb-{{ config.icon_color }}
      entity: input_boolean.3d_printer_camera_view
      tap_action:
        action: toggle
      double_tap_action:
        action: call-service
        service: input_boolean.toggle
        target:
          entity_id: input_boolean.3d_printer_stl_preview
      hold_action:
        action: navigate
        navigation_path: /lovelace/3d-printer
      card_mod:
        style:
          mushroom-shape-icon$: |
            .shape {
              --shape-color: none;
            }
          .: |
            ha-card {
              position: absolute;
              top: 0px;
              border: none;
            }
            ha-state-icon {
              animation: print 1s linear infinite alternate;
            }
            @keyframes print {
              0% { transform: translateX(4px); }
              30% { clip-path: polygon(0 0, 100% 0%, 100% 100%, 0 100%, 0 26%); }
              100% { transform: translateX(-4px); clip-path: polygon(0 0, 100% 0%, 100% 100%, 40% 100%, 0 26%); }
            }
  - type: conditional
    conditions:
      - condition: state
        entity: input_boolean.3d_printer_camera_view
        state: 'on'
    card:
      type: custom:swipe-card
      reset_after: 5
      start_card: 1
      parameters:
        slidesPerView: 2
        preloadImages: true
        effect: flip
        pagination:
          type: bullets
      cards:
        - type: picture-entity
          entity: camera.octoprint_camera
          show_name: false
          show_state: false
          camera_view: live
          aspect_ratio: '4:3'
        - type: picture-entity
          entity: camera.slicer_preview
          show_state: false
          show_name: false
          aspect_ratio: '4:3'

Actually, after a little bit of testing I discovered there IS an issue with the conic gradient section. If print progress is null, then there is no colored ring generated. This results in the Operational state not having a green ring after a system restart. I also found out the name of a few other printer statuses, one of which I added into my code, ‘Offline after error’.

I moved the if statement structure around to fix this issue and hopefully provide some more clarity to the background param. For statuses that don’t require print progress to be shown, I changed the percent fill from the sensor’s state to 100%.

.shape {
  {% if is_state('sensor.octoprint_print_status','Printing') or
  is_state('sensor.octoprint_print_status','Resuming') %}
    background: radial-gradient(var(--card-background-color) 60%, transparent 0%), conic-gradient(rgb(252,109,9) {{ states('sensor.octoprint_print_progress') | round(0) }}% 0%, var(--card-background-color) 0% 100%);
  {% elif is_state('sensor.octoprint_print_status','Operational') %}
    background: radial-gradient(var(--card-background-color) 60%, transparent 0%), conic-gradient(rgb(53,190,37) 100% 0%, var(--card-background-color) 0% 100%);              
  {% elif is_state('sensor.octoprint_print_status','Cancelling') or
  is_state('sensor.octoprint_print_status','Error') or
  is_state('sensor.octoprint_print_status','Offline after error')%}
    background: radial-gradient(var(--card-background-color) 60%, transparent 0%), conic-gradient(red 100% 0%, var(--card-background-color) 0% 100%);              
  {% else %}
    background: radial-gradient(var(--card-background-color) 60%, transparent 0%), conic-gradient(#9e9e9e {{ states('sensor.octoprint_print_progress') | round(0) }}% 0%, var(--card-background-color) 0% 100%);
  {% endif %} 
}

That fixed it. I kept copying and pasting different sections of the code, and then find / replace for the sensor name, and I wasn’t getting anywhere. Thanks for finding the bug!

Now I can concentrate figuring out on a pseudo state for ‘resuming’, since that’s not a built in option for me.

@gurubara

I may have found a bug in the time calculation:

My guess is that it has to do with the GMT offset, since EST is -5 UTC. Current time is 19:19 EST (00:19 UTC).

Edit:

I checked the timestamp for .day in the Template editor, and they are one day apart, which I believe confirms my theory.

In theory, I should be able to apply as_datetime|as_local to to values, but I haven’t quite got it to work yet. Hopefully that would put the PrusaLink timestamp into local.

I know I had to set UTC the offset on my MK4 when I set it up. This may not be an issue on the MK3s.

Good catch @tamorgen, I was comparing the local time, now(), to a UTC time, the sensor string. I think there are two solutions to this issue. One is to convert the sensor time to local as you suggested, I think the below template is correct:

{{ (as_datetime(states('sensor.prusalink_print_finish')) | as_local).day }}

Alternate solution is to use utcnow() instead of now() for comparison, so that both times are UTC. I updated my last post to use utcnow().

Thanks, I wasn’t aware of the utcnow(). I’ll give it a shot this evening and see how it fares. I’ll let you know how it goes.

Very brilliant )))

@tamorgen
Would you mind posting your full code?
I’ve tried grabbing the bits and pieces as you’ve posted in this thread. I am also using Prusalink so it looks like your code will be closer to what I need than the octoprint version.

Can ANYONE provide the complete working code (vs it being split up and edited over multiple posts)? TIA