Food Labels via a Dymo Label Printer

We’ve always labelled food which goes in the freezer, it makes a freezer rummage much easier, and avoid mystery meals.

The Dymo printer does a decent job, but it’s really limited to desktop computers (unless you buy yet another dymo), which makes it a pain to print the food labels. My handwriting beyond abysmal…

Obligatory Video

First, there isn’t a home assistant integration for a dymo label printer, so we’re in to dirty hacks pretty quickly.

First, setup lprint on a linux box, the instructions seemed to work fine for my LabelWriter 450 Duo.

Next problem, lprint it doesn’t take text files directly, You’ll see it needs PNG files, which ImageMagick can do relatively easily. It doesn’t automatically resize based on content length, so I added a little bit of branch logic based on the size of the first line. The last line finishes with the number of labels required

wishy@niska:~$ cat printlabel.sh
#!/bin/bash

declare -a lines

readarray -d "\n" lines <<< "$1"

char_count=${#lines[0]}

label=$(head -c -3 <<<"$1")
prints=$(tail -c 2 <<<"$1")

if [[ $char_count -lt 13 ]]; then
  convert -size 673x378 xc:white -font "AvantGarde-Book" -pointsize 96 -fill black -annotate +30+100 "$label" image.png
else
  convert -size 673x378 xc:white -font "AvantGarde-Book" -pointsize 64 -fill black -annotate +30+130 "$label" image.png
fi
lprint image.png -o media=oe_md-multipurpose-label_2.25x1.25in -n "$prints"

We can test using

./printlabel.sh 'Toad in the Hole\n2 Portion\n10/03/2024,1'

Now, how do we hook that up to home assistant. First, write a short calling script. This SSHs to the linux box and runs the print command, you’ll need to set up SSH keys for authentication from the homeassistant user. I added a little escaping for ’ as is breaks the script

root@nandi:/home/homeassistant# cat printlabel.sh
#!/bin/bash
MESSAGE=$(cat)
CLEAN_MESSAGE=$(echo "$MESSAGE" | tr -d "'")
/usr/bin/ssh [email protected] "./printlabel.sh '$CLEAN_MESSAGE'"

And we can hook that up via command line notify

command_line:
  - notify:
      command: /home/homeassistant/printlabel.sh
      name: "Print Dymo Label"

Finally, the voice bit! We could just work directly from a single prompt, but I decided that I probably didn’t want labels printed until I’ve had a chance to see what speech to text has come back with. Hence one automation to create labels and save these to helpers

alias: Dymo Create Label by Voice
description: ""
trigger:
  - platform: conversation
    command:
      - >-
        [Create|Print] [a] [dymo|food] label {quantity} [portions|portion] [of]
        {food} 
condition: []
action:
  - service: input_text.set_value
    metadata: {}
    data:
      value: "{{ trigger.slots.food |title}}"
    target:
      entity_id: input_text.dymo_food_label
  - service: input_text.set_value
    metadata: {}
    data:
      value: "{{ trigger.slots.quantity }}"
    target:
      entity_id: input_text.dymo_food_portion
  - set_conversation_response: OK, {{ trigger.slots.food | title}}. Say 'print 2 labels'
mode: single

and another to actually print. I had some problems here, I need to pass an integer number of prints to the script, but speech-to-text tends to use words rather than digits. It would be handy if custom sentence could somehow be cast as integers with some reasonably logic around it, but for the moment, I’ve just bodged some find and replace logic for two->2. I also found some words are commonly mistaken by speech-to-text (Too instead of two, Free instead of Three) and hard coded some corrections in

alias: Dymo Label - Print Food Label (Voice)
description: ""
trigger:
  - platform: state
    entity_id:
      - input_button.dymo_print_label
  - platform: conversation
    command:
      - Print {number} Labels
      - Print Label
      - Print [1|one|a] [Label|Labels]
condition: []
action:
  - if:
      - condition: template
        value_template: "{{ trigger.slots.number|length != 0 }}"
      - condition: template
        value_template: >-
          {{trigger.slots.number|replace('one','1')|replace('to','2')|replace('too','2')|replace('two','2')|replace('free','3')|replace('three','3')|replace('four','4')|replace('five','5')|replace('six','6')|int<7}}
    then:
      - service: notify.print_dymo_label
        data:
          message: >-
            {{states('input_text.dymo_food_label')}}\n{{states('input_text.dymo_food_portion')}}
            Portion\n{{now().day}}/{{now().month}}/{{now().year}},{{trigger.slots.number|replace('one','1')|replace('two','2')|replace('to','2')|replace('too','2')|replace('free','3')|replace('three','3')|replace('four','4')|replace('five','5')|replace('six','6')}}
    else:
      - service: notify.print_dymo_label
        data:
          message: >-
            {{states('input_text.dymo_food_label')}}\n{{states('input_text.dymo_food_portion')}}
            Portion\n{{now().day}}/{{now().month}}/{{now().year}},1
mode: single

Final result, it works, even if there are some dirty hacks.
As far as I can see I’m the first to hook up a Dymo to home assistant, so I hope it’s useful for others in the future.

Truly awesome … I LOVE IT!

The results of the contest are out!
They may be of interest to you :wink:
Have a look!

1 Like

Love this! Finally a way to get rid of that pesky Dymo software.

I made a few changes to your script to make it work better for my use-case:

#!/bin/bash

declare -a lines

readarray -d "\n" lines <<< "$1"

char_count=${#lines[0]}

label=$(head -c -3 <<<"$1")
prints=$(tail -c 2 <<<"$1")

convert -size 673x378 -background white -fill black -font "AvantGarde-Book" -gravity Center caption:"$label" image.png
lprint image.png -n "$prints"

Using caption:

  • the content now is now auto wrapped
  • when specified without a pointsize, the content is scaled to the maximum available size

I encouraged the lprint author to make a docker compatible version, then we could add this as a HA add-on. Great work!

So, after spending some time with your work I think I simplified some stuff and made it work a little better for me.

Shell script

On my HA install, I created a shell script which remotely executes all commands over SSH.

/config/labelprinter/printlabel.sh:

#!/bin/bash
ssh -o StrictHostKeyChecking=accept-new -i /config/.ssh/id_ed25519 [email protected] "convert -size 510x280 -background white -fill black -font 'AvantGarde-Book' -gravity Center caption:'$1' label.png;/snap/bin/lprint label.png -n '$2'"

Requires SSH keys generated and saved in in /config/.ssh

Shell command

This shell script is executed in turn by the shell command integration.

Config.yaml:

shell_command:
  print_label: "/config/labelprinter/printlabel.sh '{{content}}' '{{copies}}'"

Creating helpers:

  • input_button.print_text_label
  • input_text.label_text
  • input_number.label_copies

Creating the automation:

alias: Print text label
description: ""
triggers:
  - trigger: state
    entity_id:
      - input_button.print_text_label
conditions: []
actions:
  - action: shell_command.print_label
    data:
      content: "{{ states('input_text.label_text', with_unit=True) }}"
      copies: "{{ states('input_number.label_copies') | round(0) }}"
mode: queued
max: 10

Thanks again for your work! Hope this benefits others.

2 Likes

Hey @wishy - this is awesome! I’m planning on setting it up myself. I noticed that you’re using a Dymo 450 Duo. Do you have it currently setup so that you can print both types of labels? Or do you only use the larger slot?