#```

1 messages Β· Page 1 of 1 (latest)

sleek sedge
#

Ok... so just to make sure I understand, I would create a new sensor with this as a template?

unborn void
#

Make a template sensor

summer vortexBOT
sleek sedge
#

Ok That I can figure out, I have a lot of example on this.

Thanks so much!! I'll let you know

sleek sedge
#

This is what I've done. I must missing just something simple I guess....

  • name: 3d_printer_thumbnails_path
    unique_id: "293988e9be-c910-4634-8205-38d53170d5a7"
    state: '{% set dir = states('sensor.3d_printer_current_print') %}
    {% set img = states('sensor.3d_printer_object_thumbnails') %}
    {{ [dir.split('/')[0], img] | join('/') }}'
    attributes:
    friendly_name: "Object Thumbnails Final"
    icon: mdi:image

but I'm getting an error "can not read a block mapping entry; a multiline key many not be an implicit key

unborn void
#
state: >
  {% ....
sleek sedge
#

Ok figured it out, thanks so much..

  • name: 3d_printer_thumbnails_path
    unique_id: "192.168.168.293988e9be-c910-4634-8205-38d53170d5a7"
    state: >
    {% set dir = states('sensor.3d_printer_current_print') %}
    {% set img = states('sensor.3d_printer_object_thumbnails') %}
    {{ [dir.split('/')[0], img] | join('/') }}
    attributes:
    friendly_name: "Object Thumbnails Final"
    icon: mdi:image
violet iron
#

Hi

sleek sedge
#

Hi

violet iron
#

Does it let you edit your email comments on github?

sleek sedge
#

Let me check

#

I just did not sure I did the right thing though. didn't have any preview

violet iron
#

I think because it was originally through email it just keeps it br0ken 😦

#

(code tags)

sleek sedge
#

I add another comment and make it right this time

violet iron
#

as it looks like you did it right

#

ok

sleek sedge
#

There you go

#

much nicer

violet iron
#

Add the |urlencode fix as well

sleek sedge
#

and for the current_layer and total_layer would you have a clue on how to extract the value from the print_stats query?

violet iron
#

I tested the directory thing first with out the + in the file name and I was like what it's working fine... then I realized I already uploaded that stl so it already had a copy of the image in the main .thumbs folder for it and was just loading that one πŸ˜…

sleek sedge
#

I've tried to based it on other sensors in the yaml file but nothing worked.

sleek sedge
#

Quite sure we could make the thumbnail one only one sensor not two like I did.

violet iron
#

Can you explain more about it though where are you seeing it not update these values or it's just not accurate?

sleek sedge
#

In the one you have in the moonraker file, the current_layer is computed from the z height and the object_height and the layer_height where as with the gcode in the slicer sending the layer number at each layer change then the print_stats do have the exact layer number without needing any computation.

{"result": {"eventtime": 88572.403989076, "status": {"print_stats": {"filename": "Mobius/Mobius Extruder_Accent-Anycubic Mega X-Sparta 3D ABS+.gcode", "total_duration": 5227.189836756006, "print_duration": 3783.9447762640048, "filament_used": 5007.582759999996, "state": "printing", "message": "", "info": {"total_layer": 109, "current_layer": 12}}}}}
#

usually these values are null hence your check for unknow or unavailable

#

To populate those as I explained you need to add one Gcode in the start-gcode and one in the before each layer gcode in the printer settings

violet iron
#

Ok I understand now lets try it give me a moment while I add that to SuperSlicer

sleek sedge
#

I've tried this with no luck

- name: 3d_printer_current_layer
  unique_id: "192.168.168.296a77acc1-8134-4354-b2f6-390adab81993"
  state: '{{ states.printer_3d_layers.attributes["print_stats"]["info"][2] }}'
  icon: mdi:counter
  attributes:
    friendly_name: "Current Layer"
#

For SS
Start
SET_PRINT_STATS_INFO TOTAL_LAYER=[total_layer_count]

and before layer change:
SET_PRINT_STATS_INFO CURRENT_LAYER=[layer_num]

violet iron
#

Did you try to add those in your printer.cfg?

sleek sedge
#

no because the SET_PRINT_STATS_INFO CURRENT_LAYER=[layer_num] get's inserted in the gcode file at each layer change. That wouldn't work in the printer.cfg. Maybe the total_layer count would but not the other

violet iron
#

ok

#

Do you get values here before the print starts?

"info": {"total_layer": null, "current_layer": null}
sleek sedge
#

You mean once you launched the print but before it actually reads the file or while the printer is idling

violet iron
#

While it's warming up

sleek sedge
#

If I recall, you should have the total_layer if I recall. I have a print running now so hard for me test..
Have you checked if the gcode file has the inserted tags

violet iron
#

What is the gcode for it?

sleek sedge
#

You should see this in the gcode file

M73 P0 R26
;TYPE:Custom
M104 S0 ; Stops PS/SS from sending temp waits separately
M140 S0
SET_PRINT_STATS_INFO TOTAL_LAYER=50
START_PRINT BED=105 HOTEND=245 CHAMBER=46 FILAMENT=ABS
M107
G21 ; set units to millimeters
G90 ; use absolute coordinates
M82 ; use absolute distances for extrusion
G92 E0
; Filament gcode

SET_PRESSURE_ADVANCE extruder=extruder advance=0.45
;_TOOLCHANGE 0
M107
;LAYER_CHANGE
;Z:0.25
;HEIGHT:0.25
;BEFORE_LAYER_CHANGE
SET_PRINT_STATS_INFO CURRENT_LAYER=0
TIMELAPSE_TAKE_FRAME
;0.25
G1 E-6 F3000
M73 P1 R26
G1 Z0.25 F10800
;AFTER_LAYER_CHANGE
;0.25
M104 S245 ; set temperature
G92 E0
G1 Z0.4

#

and so on at each layer change...

violet iron
#

Ok so it's working... but I see that it won't show the values until after heating up

M107
M190 S55 ; set bed temperature and wait for it to be reached
M104 S215 ; set temperature
;TYPE:Custom
SET_PRINT_STATS_INFO TOTAL_LAYER=33
#

I'll modify that for now.

sleek sedge
#

ok well depends where you put it in your GCode Start. Mine goes like this:

M104 S0 ; Stops PS/SS from sending temp waits separately
M140 S0
SET_PRINT_STATS_INFO TOTAL_LAYER=[total_layer_count]
START_PRINT BED=[first_layer_bed_temperature] HOTEND={first_layer_temperature[initial_extruder]+extruder_temperature_offset[initial_extruder]} CHAMBER=[chamber_temperature] FILAMENT={filament_type[1]}

#

so before actually starting the macro

#

My gcode file then shows:

M73 P0 R26
;TYPE:Custom
M104 S0 ; Stops PS/SS from sending temp waits separately
M140 S0
SET_PRINT_STATS_INFO TOTAL_LAYER=50
START_PRINT BED=105 HOTEND=245 CHAMBER=46 FILAMENT=ABS
M107
G21 ; set units to millimeters
G90 ; use absolute coordinates
M82 ; use absolute distances for extrusion

violet iron
#

do you have multiple "CURRENT_LAYER" throughout the file or only at the end?

sleek sedge
#

yes

#

at each layer change

violet iron
#

Hmm only shows up at the end here

#

Are you supposed to put it in the start as well?

sleek sedge
#

Where did you put it. you have to put it in the third section: Before layer change GCode

violet iron
#

Ah yes that is where I went wrong.

#

Yay!

"info": {"total_layer": 26, "current_layer": 0}
#

Ok now lets check out home assistant

#

I added SET_PRINT_STATS_INFO CURRENT_LAYER=0 after TOTAL_LAYER is set in the start.

sleek sedge
#

Cool!! I have a few for you after this one! πŸ™‚

#

I'm really curious to see how, I've tried some many ways. Sure it's something stupid I didn't do...

sleek sedge
#

Just curious, Is it a Trident or a V0.1?

sleek sedge
#

Well not sure what time zone you are but I'm on EDT and was up pretty early this morning. I'll catchup tomorrow .

violet iron
#

V0.1 you?

#

Same

#

I would like to animate the icon of the layers but that's a lot of CSS for now.

sleek sedge
#

I have all my parts printed for my Voron 2.4r2 which I will order Monday! Right now a highly modified Anycubic Mega X

violet iron
#

Very nice! Hopefully they don't release r3 a week later like they did with the v0.2 to me haha πŸ˜„

sleek sedge
#

At some point, we'd always be in a waiting state!!! If so it give me one more reason to upgrade it!

violet iron
#

Did you test if that code works multiple directories deep?

sleek sedge
#

No I havent

violet iron
#

Hard to compute how every user is going to break something πŸ˜„

sleek sedge
#

Will you be adding the details about the Start Gcode and before layer gcode in the Readme?

#

Oh yeah...

violet iron
#

Yes

sleek sedge
#

Whenever you need someone to test any of that stuff, let me know... I enjoy doing this...

violet iron
#

Maybe @unborn void knows how to make it work with multiple directories deep? {{ [dir.split('/')[0], img] | join('/') }}

    - name: 3d_printer_object_thumbnails_path
      unique_id: "192.168.168.293988e9be-c910-4634-8205-38d53170d5a6"
      state: '{{ states.sensor.printer_3d_file_metadata.attributes["thumbnails"][1]["relative_path"] }}' 
      attributes:
        friendly_name: "Object Thumbnails Path"
        
    - name: 3d_printer_thumbnail
      unique_id: "192.168.168.293988e9be-c910-4634-8205-38d53170d5a7"
      state: >
          {% set dir = states('sensor.3d_printer_current_print') %}
          {% set img = states('sensor.3d_printer_object_thumbnails_path') %}
          {{ [dir.split('/')[0], img] | join('/') }}
      attributes:
        friendly_name: "Object Thumbnail"
        icon: mdi:image
unborn void
#

look up how to slice lists

#

it depends on how many you have and what you want to trim, so every case will be different

violet iron
#

What if its random amount for whatever the crazy user does?

unborn void
#

e.g. dir.split('/')[0] just gives the first directory. dir.split('/')[-1] gives last. Random will not work because you need to know the actual number.

violet iron
#

no direct, 1 directory, 1000 directories deep etc

unborn void
#

if you want everything before the last... dir.split('/')[:-1]

sleek sedge
#

There you go!! πŸ™‚

unborn void
#

everything after the first dir.split('/')[1:]

sleek sedge
#

I guess it would be everything before the last!!

unborn void
#

everything before the last 2.. dir.split('/')[:-2]

#

Gotta run, you get the idea

violet iron
#

Yes thank you very much!

sleek sedge
#

Thanks

#

I guess we just need to change it to [:-1] instead of [0] and this should do the job

violet iron
#

Lets hope so just wondering what it will do with no directory deep.

sleek sedge
#

Hum, right... easy to test though it worked when it wasn't in a subdirectory.

#

Strange enough the Mainsail integration doesn't publish the current layer...!!

violet iron
#

?

sleek sedge
#

There is a mainsail integration already in HA

violet iron
violet iron
#

in hacs?

sleek sedge
#

Probably the first one I installed and then I found one for Moonraker.

sleek sedge
# violet iron What else were you thinking?

I had issues with Filament but it's working now !!! I was also trying to narrow down the ETA but I think your method is quite close. I was just wondering if you were taking into account the warmup time but I think you are

#

You have narrowed down pretty much everything... Great job!

violet iron
#

Well if you think of anything toss it in the discussion or issue tracker on github. We can work on it hopefully. Thanks for your help. Just going to poke at the directory stuff then commit it.

sleek sedge
#

@violet iron just launched a print and modified the thumbnail sensor with [:-1] . Seems to work but... the returned path is : ['Voron']/.thumbs/z_motor_mount_a_x2-Anycubic Mega X-Sparta 3D ABS+-400x300.png so not sure if it works or not because usually it caches the last path

sleek sedge
sleek sedge
violet iron
#

I have yet to figure out how to get the RPi MainsailOS out of UTC mode my KlipperScreen shows UTC as well. I tried to do raspi-config on the terminal to change the TimeZone but I think it said it was missing files and couldn't change it. Have yet to look at it again.

sleek sedge
#

Well on my raspi I've got the right timezone but not in HA. And I can confirm that replacing [0] with [:-1] screws up the path and doesn't work.

#

Question, why adding 2 hours to the as_timestamp(now)

state: '{{ (as_timestamp(now())**+2*60*60**+((states.sensor.printer_3d_sensor.attributes["print_stats"]["print_duration"]/states.sensor.printer_3d_sensor.attributes["display_status"]["progress"]- states.sensor.printer_3d_sensor.attributes["print_stats"]["print_duration"]) if states.sensor.printer_3d_sensor.attributes["display_status"]["progress"]>0 else 0)) | timestamp_custom("%H:%M:%S", 0)}}'
sleek sedge
violet iron
#
     - name: 3d_printer_object_thumbnails
       unique_id: "IP59b37837-b751-4d31-98c2-516a52edf833"
       state: >
         {% set dir = states('sensor.3d_printer_current_print') %}
         {% set img = states.sensor.printer_3d_file_metadata.attributes["thumbnails"][2]["relative_path"] %}
         {{ (dir.split('/')[:-1] + [img]) | join('/') }}
       availability: >
         {% set items = ['sensor.printer_3d_file_metadata'] %}
         {{ expand(items)|rejectattr('state','in',['unknown','unavailable'])
           |list|count == items|count }}
       icon: mdi:image
       attributes:
         friendly_name: "Object Thumbnails"
violet iron
#

I think KlipperScreen may ignore locals

#

Maybe the same is true for moonraker

#

commit uploaded to github hopefully I didn't forget anything.

#

well still have to update the readme

sleek sedge
sleek sedge
# sleek sedge Nice let me replace mine...

All good. I think I found the way to convert to my timezone in HA for the ETA. It now displays the right ETA. In the timestamp_custom, changed 0 for 5. Not sure why 5 and not -5 but it works...

    - name: 3d_printer_eta
      unique_id: "<moonraker-ip-address>a2b57068-9a32-4d2c-8cc9-57d2389a9082"
      state: '{{ (as_timestamp(now())+((states.sensor.printer_3d_sensor.attributes["print_stats"]["print_duration"]/states.sensor.printer_3d_sensor.attributes["display_status"]["progress"]- states.sensor.printer_3d_sensor.attributes["print_stats"]["print_duration"]) if states.sensor.printer_3d_sensor.attributes["display_status"]["progress"]>0 else 0)) | timestamp_custom("%H:%M:%S", 5)}}'
      availability: >
        {% set items = ['sensor.printer_3d_sensor'] %}
        {{ expand(items)|rejectattr('state','in',['unknown','unavailable'])
          |list|count == items|count }}
      icon: mdi:av-timer
      attributes:
        friendly_name: "ETA"
violet iron
sleek sedge
#

yep

#

and I confirmed as I reverted to 0 and it went back to UTC time

#

oh and I removed the 2*60*60 right after the as_timestamp(now)

violet iron
#

Good stuff why does that need to be removed? as_timestamp(now())+2*60*60+

sleek sedge
#

Well was it there, it was adding 2 hours to time(now)

#

Could be if it wasn't you, the original developer was in UTC+2 zone

violet iron
#

So basically they didn't know how to properly set the timezone at the end?

sleek sedge
#

Most probably but I'm puzzled why 5 and not -5?? I'll try to dig why. I hate doing things and not understanding the logic

violet iron
#

Haha yeah that's why I ask we are one in the same brute force and perseverance coding/discovery...

#

I found this | timestamp_local()

#

Maybe it will take from the system?

#

You want to avoid hardcoding if plausible

sleek sedge
#

So here is an explanation from Petro on a thread I found.

{{ (now().strftime("%s") | int + (15*60)) | timestamp_custom("%H:%M", false) }}

Without the false, it’s based on unix_time not local time. I’m guessing your timezone is +1? If not, you’re time is screwed up on your system and you need to make sure your OS time is set properly and your timezone is set properly in your config.

#

Strange a enough if I put False I get a wrong time but if I make it True I get the right time. I've checked and my HA Timezone is well set. So it worked with 5 because it was not "0" so declared True I guess

#

Maybe mention in the ReadMe that adding the GCode is valid for PrusaSlicer or SuperSlicer. Cura has a different way of doing this and the variables might be different.

My two cents... πŸ™‚

violet iron
#

So should all these |timestamp_custom("%H:%M:%S", 0) => |timestamp_custom("%H:%M:%S", 1) ?

#

1 being true

sleek sedge
#

no because the first one is actually a calculation of duration not a time per say

violet iron
#

I thought the ETA was just how many hours it thinks it will take not what time it was going to finish at?

sleek sedge
#

ETA is at what time it should finish and Time Remaining is the amount of time it thinks it take to complete the job

#

Just like planes!! LOL

#

And time remaining doesn't have a as_timestamp(now() at the start

violet iron
#

I changed it to 1 and removed the math at the start

#

committed!

#

1 did the same as 5 as you discovered.

#

Do you have KlipperScreen?

#

Added the Prusa/Super to the readme

sleek sedge
# violet iron I changed it to 1 and removed the math at the start

Yeah could have been True which, for me at least shows that it's not a number adding hours, but both works.
As for Klipper screen not yet but I will be testing it this afternoon on another RaspI I have on which I want to install Klipper and Klipper Screen I can report when I've done it if you want.

violet iron
#

Ok thank you

sleek sedge
#

@violet iron Just checking, are you sure the modified ObjectThumbnail sensor works? Were you checking the state of the sensor or the fact that you'd see the thumbnail in the custom-card?

#

I've just restarted my HA and the thumbnails is not displaying...

unborn void
#

why are you using timestamps whne you can use timedeltas

#

now() + timedelta(minutes=15)

sleek sedge
# unborn void `now() + timedelta(minutes=15)`

I believe this is code that @violet iron pulled from another project and he added some other features in the moonraker.yaml but those were already there I think . This is for our 3D printer HA dashboard. It calculates the remaining time and the ETA for the print to complete.

unborn void
#

yeah but it just is over complicated

#

and you're using the states object

#

which will have errors when you restart

sleek sedge
unborn void
#

I'm also not sure why you're dividing the duration by the progress

#

yeah, all those templates use the states object

#

if the templates start before the print entity, you'll have errors in your logs

#

and the templates won't be added to the system, keeping them unavailable

sleek sedge
#

Me neither LOL just know for now that it's working. What isn't working is the new sensor for the thumbnail based on your help yesterday with the directory stuff

    - name: 3d_printer_object_thumbnails
      unique_id: "IP59b37837-b751-4d31-98c2-516a52edf833"
      state: >
        {% set dir = states('sensor.3d_printer_current_print') %}
        {% set img = states.sensor.printer_3d_file_metadata.attributes["thumbnails"][2]["relative_path"] %}
        {{ (dir.split('/')[0] + [img]) | join('/') }}
      availability: >
        {% set items = ['sensor.printer_3d_file_metadata'] %}
        {{ expand(items)|rejectattr('state','in',['unknown','unavailable'])
          |list|count == items|count }}
      icon: mdi:image
      attributes:
        friendly_name: "Object Thumbnails"    
sleek sedge
unborn void
#

use state_attr('sensor.printer_3d_file_metadata', 'thumbnails')[2].relative_path

unborn void
#

based on what you explained, the code will work

#

if it's not what you explained, πŸ€·β€β™‚οΈ

#

if the relative path has a . on it, you need to remove that as well

sleek sedge
#

the relative path is as such: ".thumbs/z_motor_mount_a_x2-Anycubic Mega X-Sparta 3D ABS+.png"

and the file path is: "Voron/z_motor_mount_a_x2-Anycubic Mega X-Sparta 3D ABS+.gcode"

and the resulting sensor needs to be: "Voron/.thumbs/z_motor_mount_a_x2-Anycubic Mega X-Sparta 3D ABS+.png"

unborn void
#

then the code above is all you need

#

you can test this yourself

#

works with zero or the -1

#
{% set dir = "Voron/z_motor_mount_a_x2-Anycubic Mega X-Sparta 3D ABS+.gcode" %}
{% set img = ".thumbs/z_motor_mount_a_x2-Anycubic Mega X-Sparta 3D ABS+.png" %}
{{ (dir.split('/')[:-1] + [img]) | join('/') }}
#

use the template editor to test things

#

:-1 is the laziest way to keep it relative and a list

sleek sedge
#

ok but the filename changes everytime

unborn void
#

that shouldn't matter

#

I'm showing you it working

#

with your current filename

#

so you replace that with whatever gets the filename and whatever gets the dir

sleek sedge
#

ok so now this
{% set img = states.sensor.printer_3d_file_metadata.attributes["thumbnails"][2]["relative_path"] %}

would become
{% set img = state_attr('sensor.printer_3d_file_metadata', 'thumbnails')[2].relative_path %}

unborn void
#

yep

sleek sedge
#

Thank you and sorry for being a noob in this.

unborn void
#

keep in mind, that grabs the 3rd item in thumbnails

#

so you need to have 3 items in your list for that to always work

#

if you don't have 3, that will fail

sleek sedge
#

Ok so like we were saying this morning, if say the file name would Voron/subdir/filename.gcode that wouldn't work?
The relative path is always .thumbs/filename.gcode whether its 1, 2 or more directory deep..

unborn void
#

then you should be also parsing the image directory

#

if you just want to get the filename then you need to parse both

#

not just the dir

sleek sedge
#

yeah but the API always returns .thumbs/image.png even if the file has 2,3 or more subdirectory in front of it. It's relative to the gcode file itself and not relative to the main directory.

#

Not sure why the moonraker API doesn't return the right path.

unborn void
#

You have to provide other examples, becuase what your'e saying doesn't make sense to me

#

so show me an example of a situation you think that won't work and the expected path you want out of it

sleek sedge
#

So here is the results which gives us the file being printed:

http://192.168.168.29:7125/printer/objects/query?heater_bed&extruder&print_stats&toolhead&display_status&virtual_sdcard&gcode_move&filament_switch_sensor Filament&temperature_sensor Chamber_Temp"

and this is the result:

{"result": {"eventtime": 35728.016348297, "status": {"heater_bed": {"temperature": 99.95, "target": 100.0, "power": 0.8324215370599557}, "extruder": {"temperature": 239.87, "target": 240.0, "power": 0.455732523486926, "can_extrude": true, "pressure_advance": 0.45, "smooth_time": 0.04}, "print_stats": {"filename": "Voron/z_motor_mount_a_x2-Anycubic Mega X-Sparta 3D ABS+.gcode", "total_duration": 14117.065496281, "print_duration": 11561.703145902004, "filament_used": 11818.283110000018, "state": "printing", "message": "", "info": {"total_layer": 210, "current_layer": 19}}, "toolhead": {"homed_axes": "xyz", "axis_minimum": [-5.0, 0.0, -5.0, 0.0], "axis_maximum": [300.0, 300.0, 288.0, 0.0], "print_time": 35714.14340374245, "stalls": 0, "estimated_print_time": 35711.84534275, "extruder": "extruder", "position": [83.827, 212.408, 3.9972802385648096, 11818.283110000018], "max_velocity": 300.0, "max_accel": 1250.0, "max_accel_to_decel": 1900.0, "square_corner_velocity": 5.0}, "display_status": {"progress": 0.31, "message": "Printing..."}, "virtual_sdcard": {"file_path": "/home/pi/gcode_files/Voron/z_motor_mount_a_x2-Anycubic Mega X-Sparta 3D ABS+.gcode", "progress": 0.3241902194042416, "is_active": true, "file_position": 7038205, "file_size": 21710109}, "gcode_move": {"speed_factor": 1.0, "speed": 4500.0, "extrude_factor": 1.0, "absolute_coordinates": true, "absolute_extrude": true, "homing_origin": [0.0, 0.0, -0.015, 0.0], "position": [83.827, 212.408, 4.035, 11818.283110000018], "gcode_position": [83.827, 212.408, 4.05, 5.269580000000133]}, "filament_switch_sensor Filament": {"filament_detected": true, "enabled": true}, "temperature_sensor Chamber_Temp\"": {}}}}
#

the other call is :http://192.168.168.29:7125/server/files/metadata?filename=Voron%2Fz_motor_mount_a_x2-Anycubic Mega X-Sparta 3D ABS%2B.gcode

and the result is:

{"result": {"size": 21710109, "modified": 1675521154.495122, "uuid": "61093ce6-1e17-45b4-81d2-bdffd0dbc12a", "slicer": "SuperSlicer", "slicer_version": "2.5.59", "gcode_start_byte": 53496, "gcode_end_byte": 21694499, "layer_count": 210, "object_height": 42.2, "estimated_time": 34020, "nozzle_diameter": 0.4, "layer_height": 0.2, "first_layer_height": 0.25, "first_layer_extr_temp": 245.0, "first_layer_bed_temp": 105.0, "chamber_temp": 46.0, "filament_name": "Sparta 3D ABS+", "filament_type": "ABS", "filament_total": 35228.06, "filament_weight_total": 87.28, "thumbnails": [{"width": 32, "height": 32, "size": 848, "relative_path": ".thumbs/z_motor_mount_a_x2-Anycubic Mega X-Sparta 3D ABS+-32x32.png"}, {"width": 400, "height": 300, "size": 25575, "relative_path": ".thumbs/z_motor_mount_a_x2-Anycubic Mega X-Sparta 3D ABS+-400x300.png"}], "print_start_time": 1675521155.121734, "job_id": "0002C0", "filename": "Voron/z_motor_mount_a_x2-Anycubic Mega X-Sparta 3D ABS+.gcode"}}

so what I'm saying is that in the second call relative with always be with .thumbs/<filename> .png
even if the filename in the first call would be subdir1/subdir2/subdir3/<filename>.gcode

unborn void
#

I still don't see what you're saying

#

are you using filename correctly when responding? Did you mean directory?

sleek sedge
unborn void
#

those examples show that they would work with the previous code

sleek sedge
#

Yes this works. I'm not saying it not. Basically what I'm wondering and as you mentioned I'll test in the developer tools template is if it would work if the gcode file would be deeper than one subdirectory. For now yes should work. I will test it in a minute

#

Ok the parsing of the filename works well if I use the developer templates with pasted filenames
Voron/dir1/dir2/.thumbs/filename.png

but seems the sensor is not getting the filename from this:
state_attr('sensor.printer_3d_file_metadata', 'thumbnails')[2].relative_path

#

the state of the sensor is still unavailable..

unborn void
#

if the sensor is unavailable, then you need to look at errors in your logs or your availability template

sleek sedge
#

And a dumb question... How can I paste a clipped image in discord?

#

I tried just ctrl V but with no success.

summer vortexBOT
#

Please use imgur or other image sharing web sites, and share the link here.

Image posting is blocked in most channels to discourage people from sharing text as images. Sharing text as images assumes that everybody sees the world as you do, which isn't the case. Some people are colour blind, or have visual impairment that means they can't make sense of an image of text.

unborn void
#

Also, there's text logs you can just copy/paste from

#

config/homeassistant.logs

sleek sedge
#

OK this doesn't seem to return the relative path as it was before:

state_attr('sensor.printer_3d_file_metadata', 'thumbnails')[2].relative_path

unborn void
#

if your last result is the same as now, you only have 2 items in your thumbnail list

#

which is why I said it would break if you didn't have 3 items

#

the [2] grabs the 3rd item

sleek sedge
#

there will always be only 2. one is 32x32 png file and the other one is a 400x300 png file

unborn void
#

then you should be using [1] for the 2nd item

sleek sedge
#

ok

#

All good! Thanks so much for your patience...

#

So what I understand is that through all these sensor, would be better to use the state_attr instead of the states object when we need to pull from the metadata?

#

Or was it just in this particular case

#

@violet iron Here is the final sensor template which with the great help of @unborn void πŸ™ will pull the right path for the thumbnail even if it's deep down in a few subdirectories.

    - name: 3d_printer_object_thumbnails
      unique_id: "IP59b37837-b751-4d31-98c2-516a52edf833"
      state: >
        {% set dir = states('sensor.3d_printer_current_print') %}
        {% set img = state_attr('sensor.printer_3d_file_metadata', 'thumbnails')[1].relative_path %}
        {{ (dir.split('/')[:-1] + [img]) | join('/') }}
      availability: >
        {% set items = ['sensor.printer_3d_file_metadata'] %}
        {{ expand(items)|rejectattr('state','in',['unknown','unavailable'])
          |list|count == items|count }}
      icon: mdi:image
      attributes:
        friendly_name: "Object Thumbnails"    

#

This is where all the data is being used

violet iron
#

Basically the quality of the thumbnail, and the software always generates 3 for each gcode file.

#

Why mine was still working is because I generated my picture entity from the yaml code which is getting depreciate so that is why it worked πŸ˜„

#

So good that you tried it.

#

the weird thing is why it works maybe from the friendly name or something.

#

as when I break that thumbnail code directory it still breaks the prior yaml defined picture box

#

even though it's not pointed at object_thumbnail and just thumbnail

#

It's weird that it never purges it even though it's commented out you can see here it is grabbing the state from object_thumbnails it itself is called 3d printer thumbnail and that is why it was still working for me πŸ˜„

#camera:
#  Loading generic IP camera via configuration.yaml is deprecated.
#  - platform: generic
#    name: "3D Printer Thumbnail"
#    still_image_url: http://IP:7125/server/files/gcodes/{{ states("sensor.3d_printer_object_thumbnails") }}
#    verify_ssl: false
violet iron
#
{"result": {"size": 860653, "modified": 1673834382.0390553, "uuid": "4a46a45a-86b9-437b-9192-798e5eeccf0d", "slicer": "SuperSlicer", "slicer_version": "2.4", "gcode_start_byte": 268511, "gcode_end_byte": 846262, "layer_count": 247, "object_height": 12.5, "estimated_time": 2743, "nozzle_diameter": 0.4, "layer_height": 0.05, "first_layer_height": 0.2, "first_layer_extr_temp": 215.0, "first_layer_bed_temp": 55.0, "chamber_temp": 15.0, "filament_name": "Basic PLA @VORON", "filament_type": "PLA", "filament_total": 341.64, "filament_weight_total": 1.02, "thumbnails": [{"width": 32, "height": 24, "size": 1647, "relative_path": ".thumbs/2_Skirt_Clip-32x32.png"}, {"width": 64, "height": 64, "size": 6338, "relative_path": ".thumbs/2_Skirt_Clip-64x64.png"}, {"width": 400, "height": 300, "size": 186843, "relative_path": ".thumbs/2_Skirt_Clip-400x300.png"}], "print_start_time": 1674811761.6515377, "job_id": "000058", "filename": "2_Skirt_Clip.gcode"}}
"thumbnails": [{"width": 32, "height": 24, "size": 1647, "relative_path": ".thumbs/2_Skirt_Clip-32x32.png"}, {"width": 64, "height": 64, "size": 6338, "relative_path": ".thumbs/2_Skirt_Clip-64x64.png"}, {"width": 400, "height": 300, "size": 186843, "relative_path": ".thumbs/2_Skirt_Clip-400x300.png"}],
#

Gotta love nonstandard all over the board things...

#

So that may need more tweaking and check for if the higher quality image is in spot [1] or [2]

#

@sleek sedge why did it not generate the 64x64 image in slot 1 for that print?

#

What slicer do you use?

#

Were you getting this error:

No image source configured
show_state: false
show_name: false
camera_view: auto
type: picture-entity
entity: sensor.3d_printer_object_thumbnails
#

Guess you have to manually add the IP camera to that url now without the yaml depreciation code

#
http://IP:7125/server/files/gcodes/{{ states("sensor.3d_printer_object_thumbnails") }}
#

Technically could we just add the http to the sensor to do away with the manual webui entry of the camera or you already figured out this?

sleek sedge
#

There is no way to copy/paste pictures in the chat beside using imgur?

violet iron
#

all 3

#

Are you using current versions?

#

I was using 2.4 of superslicer and 2.6 of prusa

sleek sedge
#

I'm using 2.5.59.2 but even with the previous versions I've always had only 2.

violet iron
#

So why do I have 3 πŸ˜„

sleek sedge
#

where do you set that 64x64 size

violet iron
#

I never set it default settings.

sleek sedge
#

I've never ran 2.4 maybe it's something that is in 2.5

violet iron
sleek sedge
#

Definitely different in 2.5 as you can see

violet iron
#

That's Prusa 2.6

sleek sedge
#

Ok but where is the 3rd one coming from...

#

32x32

violet iron
#

I was thinking 32 is the standard one that it always does from what you were showing in your screenshot

#

and those are the extra two it adds

sleek sedge
#

I've set it to 32x32 and 400x300 in the Thumbnails section of the Printer Settings

#

I've never used Prusa Slicer as I'm kind of new ( less than a year) and went from Cura/Marlin to Klipper/Slicer pretty much 1 week after getting my printer...

violet iron
#

I was wondering why the original screenshots from the other repos had crystal clear thumbs on [1] where mine were all grainy...

sleek sedge
#

That would a good reason... πŸ™‚

violet iron
#

That's when I saw that [1] for me was 64x64

sleek sedge
#

Maybe time to upgrade to the 2.5 version!! πŸ˜‰

#

You could run them in parallel in case it doesn't work out

violet iron
#

The weird thing is 2.4 shows the same as yours so maybe just a prusa thing.

#

^2.4

sleek sedge
#

Ah that could very well be if you were always using Prusa

violet iron
#

Still where does 32x32 come from...

sleek sedge
#

Hum are you saying that even by using SS you are getting a 32x32 generated?

violet iron
#

I only upload from the slicer but I will check now that we see this weirdness.

#

I would have to think that it would also do it as all my files have 3 as I just started playing with prusa 2.6alpha3 for the organic support, Ruler, Text generation.

#

Wonder if it's mainsail/klipper/ generating the 32x32

sleek sedge
#

That was exactly what I was typing when you sent it!!! LOL

violet iron
#

I bet it is because it uses those 32x32 icons for the file list.

sleek sedge
#

Ah maybe it generates it if it doesn't have it....

#

Try changing your settings to 32x32, 400x300 and see if it does generate an additional one.

#

Getting late.....

#

fingers not following my brain...

violet iron
#

Before you go how were you adding the thumbnail to homeassistant?

sleek sedge
#

I'm not going yet. got some calibration going on... πŸ™‚ I'll paste some snapshots...

violet iron
#

That shows your camera

#

What are you using for your thumbnail box

sleek sedge
#

Dah.. sorry LOL brain fart!

violet iron
#

I wish they standardize those two plugins into one.

#

MJPEG IP Camera / Generic Camera

#

I have to use Generic Camera as it's the only one with a rotation option (which should be added to mjpeg ip camera)

#

when you use the card-mod to rotate it then puts the caption text at the bottom upside down.

sleek sedge
violet iron
#

Ok so that should have worked fine with the prior code

#

as that was what I was doing

sleek sedge
#

yeah just had to change the sensor name of course

violet iron
#

but why did you have a different sensor name it was always named object_thumbnails

violet iron
#

That first section of commented out code was how the thumbnail was originally set

sleek sedge
#

Hum wasn't it printer_thumbnails originaly

#

Maybe not, we did some many tests that maybe when I did the one with the 2 different sensors I had changed it...

violet iron
#

Ah right ok

#

Hopefully we can just put it all in the sensor field and not setup the camera manually but I doubt it πŸ˜„

sleek sedge
#

Always nice to have some better goals!!!

#

Ok I'm done for tonight! Thanks for putting this together..

violet iron
#

Have a good rest!

sleek sedge
#

I'll check it out tomorrow morning

violet iron
#

Thanks for the help

violet iron
unborn void
#

You'd have to use a card that allows templating any card

#

Or make a generic camera entity

#

and display the camera as yourpicture for the card

violet iron
#
type: grid
square: false
columns: 1
cards:
  - type: picture-entity
    name: 3D Printer Thumbnail
    show_state: true
    show_name: true
    camera_view: auto
    entity: sensor.3d_printer_current_print
    image: camera.3d_printer_thumbnail
#camera:
# Loading generic IP camera via configuration.yaml is deprecated, it will be automatically imported. Once you have confirmed correct operation, please remove 'generic' (IP camera) section(s) from configuration.yaml
# Directions in the README.md for how to add the Thumbnail now.
#  - platform: generic
#    name: "3D Printer Thumbnail"
#    still_image_url: http://<moonraker-ip-address>:7125/server/files/gcodes/{{ states("sensor.3d_printer_object_thumbnails") }}
#    verify_ssl: false

Which properly displays the code from this above:

    - name: 3d_printer_object_thumbnails
      unique_id: "<moonraker-ip-address>59b37837-b751-4d31-98c2-516a52edf833"
      state: >
        {% set dir = states('sensor.3d_printer_current_print') %}
        {% set img = state_attr('sensor.printer_3d_file_metadata', 'thumbnails')[2].relative_path %}
        {{ (dir.split('/')[:-1] + [img]) | join('/') }}
      availability: >
        {% set items = ['sensor.printer_3d_file_metadata'] %}
        {{ expand(items)|rejectattr('state','in',['unknown','unavailable'])
          |list|count == items|count }}
      icon: mdi:image
      attributes:
        friendly_name: "Object Thumbnails"

Then I want this to show up at the bottom of that picture entity:

#
    - name: 3d_printer_current_print
      unique_id: "<moonraker-ip-address>3a0f3144-a801-422f-adb6-e2ed35796072"
      state: '{{ states.sensor.printer_3d_sensor.attributes["print_stats"]["filename"]}}'
      availability: >
        {% set items = ['sensor.printer_3d_sensor'] %}
        {{ expand(items)|rejectattr('state','in',['unknown','unavailable'])
          |list|count == items|count }}
      icon: mdi:file
      attributes:
        friendly_name: "Current Print"
#

ie replacing the generic name or idle words (state)

unborn void
#

well, your entity is wrong for picture-entity, should be sensor.3d_printer_current_print, not 3d_printer_current_print

#

other than that, it should work

#

keep in mind that non-live camera images only update once every 20 seconds

#
  - type: picture-entity
    name: 3D Printer Thumbnail
    show_state: true
    show_name: true
    camera_view: auto
    entity: camera.3d_printer_thumbnail

If ou want to put text on that, you might have to switch to picture elements instead.

violet iron
unborn void
#

Then your stream source is most likely wrong

#

Well, Still Image URL

violet iron
#

Yeah had some broken code above it

unborn void
#

if you can get the camera working, then you can put that anywhere

#

you will most likely want to set camera_view to live as well for your card

violet iron
#

The idle state now shows the gcode file name but the picture is still broken

#

I'll remove entity and see if the picture then works

#

Thank you it's working now https://imgur.com/a/QIBxMiA I had the camera feed in the image: spot while I was trouble shooting that idle state...

#
  - show_state: true
    show_name: true
    camera_view: live
    type: picture-entity
    entity: sensor.3d_printer_current_print
    name: Current Print
    camera_image: camera.3d_printer_thumbnail
violet iron
unborn void
#

if you don't know coding, it'll be very hard

violet iron
#

ok so scratch that I guess πŸ˜„

violet iron
# violet iron ``` type: grid square: false columns: 1 cards: - type: picture-entity name...

@unborn void How would I validate if thumbnail [2] doesn't exist in the json output then default to [1] or [0] etc?

   - name: 3d_printer_object_thumbnails
      unique_id: "<moonraker-ip-address>59b37837-b751-4d31-98c2-516a52edf833"
      state: >
        {% set dir = states('sensor.3d_printer_current_print') %}
        {% set img = state_attr('sensor.printer_3d_file_metadata', 'thumbnails')[2].relative_path %}
        {% if img is not defined %}
        {% set img = state_attr('sensor.printer_3d_file_metadata', 'thumbnails')[1].relative_path %}
        {% endif %}
        {{ (dir.split('/')[:-1] + [img]) | join('/') }}
      availability: >
        {% set items = ['sensor.printer_3d_file_metadata'] %}
        {{ expand(items)|rejectattr('state','in',['unknown','unavailable'])
          |list|count == items|count }}
      icon: mdi:image
      attributes:
        friendly_name: "Object Thumbnails"
violet iron
#

UndefinedError: list object has no element 3

#

I set 2 to 3 to see what would happen...

#

When I set it back to 2 I get:

- name: 3d_printer_object_thumbnails
      unique_id: "IP59b37837-b751-4d31-98c2-516a52edf833"
      state: >
        
        
        
        
        http://IP:7125/server/files/gcodes/some/directory1/directory2/.thumbs/pumpkaboo_print-400x300.png
      availability: >
        
        True
      icon: mdi:image
      attributes:
        friendly_name: "Object Thumbnails"
violet iron
#

It's weird because it will complete if it's properly defined with 2 but if I put 3 it errors out and won't continue with the else.

violet iron
#
    - name: 3d_printer_object_thumbnails
      unique_id: "<moonraker-ip-address>59b37837-b751-4d31-98c2-516a52edf833"
      state: >
        {% set dir = states('sensor.3d_printer_current_print') %}
        {% set thumb = state_attr('sensor.printer_3d_file_metadata','thumbnails') %}
        {% set img = (thumb | last).relative_path if thumb else 'not available' %}
        {{ (dir.split('/')[:-1] + [img]) | join('/') }}
      availability: >
        {% set items = ['sensor.printer_3d_file_metadata'] %}
        {{ expand(items)|rejectattr('state','in',['unknown','unavailable'])
          |list|count == items|count }}
      icon: mdi:image
      attributes:
        friendly_name: "Object Thumbnails"
unborn void
#

indexes start at 0

#

0 being 1st item, 1 being 2nd, 2 being 3rd

#

I'm 90% sure I've mentioned this before in this thread

#

if you always want the last item, that would be [-1], second-to-last [-2], 3rd to last [-3]

#

if the list is always changing size, you need to figure out which item you want. You can base your selection of the start of the list with a postive number or the end of a list with a negative number.

violet iron
# unborn void it's not weird

I didn't realize in the start that you have to try to complete it in the same line so it was never testing being on the second line down from where it was setting the variable above the if statement.

sleek sedge
violet iron
#

Hi You know about the moonraker integration now?

sleek sedge
#

Yeah.. I saw ater and I think it screwed my original integration but I seem to have another issue which is on the printer side. Right now even though the [virtual sd_card] module is loaded I can't make a call to print_stats I have to wait until my print finishes.

But I guess then I can disable everything we had worked together right?

violet iron
#

yes

violet iron
#

Just to note though I just tested it and have no problems

sleek sedge
# violet iron https://discordapp.com/channels/330944238910963714/1070360235027468420/107141589...

Hi Nona, my apologies, that was never my intention. Had you reached out here I would have responded for sure. That being said my issue seem to be on the klipper/moonraker side where even doing a simple http://serverip:7125/print_stats returns an error

{"error": {"code": 404, "message": "Not Found", "traceback": "Traceback (most recent call last):\n\n  File \"/home/biqu/moonraker-env/lib/python3.9/site-packages/tornado/web.py\", line 1690, in _execute\n    result = self.prepare()\n\n  File \"/home/biqu/moonraker/moonraker/app.py\", line 968, in prepare\n    raise tornado.web.HTTPError(404)\n\ntornado.web.HTTPError: HTTP 404: Not Found\n"}}
violet iron
violet iron
#

Have you played with spoolman?