Display materialdesign icons on ESPHome attached to screen

Ok, I tried the code for me, but I don’t get it working…

display:
  - platform: ssd1306_i2c
    model: "SSD1306 128x32"
    reset_pin: D0
    address: 0x3C
    lambda: |-    
      if (id(icon_ow).has_state()) {
          std::map<std::string, std::string> weather_state { 
              { "rainy", "󰖗"},             // mdi-weather-rainy
              { "cloudy", "󰖕"},           // mdi-weather-cloudy
          };
              
            it.printf(5, 5, id(font_icon), weather_state[id(icon_ow).state.c_str()].c_str());
      }
font:  
  - file: "materialdesignicons-webfont.ttf"
    id: font_icon
    size: 12
    glyphs: [
      "󰖗", # mdi-weather-rainy
      "󰖕", # mdi-weather-cloudy
    ]
sensor:
  - platform: homeassistant
    id: icon_ow
    entity_id:  weather.openweathermap
error:
src/main.cpp: In lambda function:
src/main.cpp:405:68: error: request for member 'c_str' in 'icon_ow->esphome::homeassistant::HomeassistantSensor::<anonymous>.esphome::sensor::Sensor::state', which is of non-class type 'float'
           it.printf(5, 5, font_icon, weather_state[icon_ow->state.c_str()].c_str());
                                                                    ^

Thanks for the help!

It is because of

sensor:
  - platform: homeassistant
    id: icon_ow
    entity_id:  weather.openweathermap

This sensor seems not to return a string (icon name?) but return a float.

Could you copy from dev tools > state the current state for weather.openweathermap?

Of course:

This is the yaml
temperature: 13.8
humidity: 93
pressure: 1016
wind_bearing: 240
wind_speed: 11.16
attribution: Data provided by OpenWeatherMap
forecast:
  - datetime: 1599296400000
    temperature: 13.9
    precipitation: 1.7
    condition: rainy
  - datetime: 1599307200000
    temperature: 13.8
    precipitation: 0.2
    condition: rainy
  - datetime: 1599318000000
    temperature: 16
    precipitation: 0.8
    condition: rainy
  - datetime: 1599328800000
    temperature: 13.7
    precipitation: 0.3
    condition: rainy
  - datetime: 1599339600000
    temperature: 12.1
    precipitation: null
    condition: cloudy
  - datetime: 1599350400000
    temperature: 10.3
    precipitation: null
    condition: cloudy
  - datetime: 1599361200000
    temperature: 9.4
    precipitation: null
    condition: sunny
  - datetime: 1599372000000
    temperature: 10.2
    precipitation: null
    condition: sunny
  - datetime: 1599382800000
    temperature: 15
    precipitation: null
    condition: sunny
  - datetime: 1599393600000
    temperature: 17.6
    precipitation: 0.2
    condition: rainy
  - datetime: 1599404400000
    temperature: 17.6
    precipitation: 0.2
    condition: rainy
  - datetime: 1599415200000
    temperature: 13.2
    precipitation: null
    condition: partlycloudy
  - datetime: 1599426000000
    temperature: 11.6
    precipitation: null
    condition: cloudy
  - datetime: 1599436800000
    temperature: 10.2
    precipitation: null
    condition: cloudy
  - datetime: 1599447600000
    temperature: 9.1
    precipitation: null
    condition: sunny
  - datetime: 1599458400000
    temperature: 9.9
    precipitation: null
    condition: sunny
  - datetime: 1599469200000
    temperature: 14.9
    precipitation: null
    condition: sunny
  - datetime: 1599480000000
    temperature: 16.6
    precipitation: null
    condition: partlycloudy
  - datetime: 1599490800000
    temperature: 17.3
    precipitation: null
    condition: cloudy
  - datetime: 1599501600000
    temperature: 13.3
    precipitation: null
    condition: partlycloudy
  - datetime: 1599512400000
    temperature: 11.9
    precipitation: null
    condition: partlycloudy
  - datetime: 1599523200000
    temperature: 11.6
    precipitation: null
    condition: partlycloudy
  - datetime: 1599534000000
    temperature: 11.5
    precipitation: null
    condition: cloudy
  - datetime: 1599544800000
    temperature: 12.4
    precipitation: null
    condition: cloudy
  - datetime: 1599555600000
    temperature: 17.6
    precipitation: null
    condition: cloudy
  - datetime: 1599566400000
    temperature: 21.4
    precipitation: null
    condition: cloudy
  - datetime: 1599577200000
    temperature: 21.9
    precipitation: null
    condition: sunny
  - datetime: 1599588000000
    temperature: 17.8
    precipitation: null
    condition: partlycloudy
  - datetime: 1599598800000
    temperature: 17.5
    precipitation: null
    condition: cloudy
  - datetime: 1599609600000
    temperature: 16.3
    precipitation: null
    condition: cloudy
  - datetime: 1599620400000
    temperature: 15.4
    precipitation: null
    condition: partlycloudy
  - datetime: 1599631200000
    temperature: 16.3
    precipitation: null
    condition: cloudy
  - datetime: 1599642000000
    temperature: 20.9
    precipitation: null
    condition: partlycloudy
  - datetime: 1599652800000
    temperature: 23.6
    precipitation: null
    condition: sunny
  - datetime: 1599663600000
    temperature: 22.1
    precipitation: null
    condition: partlycloudy
  - datetime: 1599674400000
    temperature: 18.2
    precipitation: 0.3
    condition: rainy
  - datetime: 1599685200000
    temperature: 14.6
    precipitation: 0.7
    condition: rainy
  - datetime: 1599696000000
    temperature: 12.1
    precipitation: null
    condition: partlycloudy
  - datetime: 1599706800000
    temperature: 11.4
    precipitation: null
    condition: sunny
  - datetime: 1599717600000
    temperature: 11.8
    precipitation: null
    condition: partlycloudy
friendly_name: OpenWeatherMap

grafik

hm, I created a sensor template with only the state.

        weather_icon:
          friendly_name: "Weather Icon"
          value_template: "{{ states('weather.openweathermap') }}"
sensor:
  - platform: homeassistant
    id: icon_ow
    entity_id:  sensor.weather_icon
src/main.cpp:405:68: error: request for member 'c_str' in 'icon_ow->esphome::homeassistant::HomeassistantSensor::<anonymous>.esphome::sensor::Sensor::state', which is of non-class type 'float'
           it.printf(30, 5, font_icon, weather_state[icon_ow->state.c_str()].c_str());

But the same error with typ casting…

Yeah and again, reading the docs correct, helped…

Note

This component is only for numeral states. If you want to import arbitrary text states from Home Assistant, use the Home Assistant Text Sensor.

text_sensor:
  - platform: homeassistant
    id: icon_ow
    entity_id:  weather.openweathermap
2 Likes

It would be amazing if one could do a VSCode extension for that :slight_smile:
Using the mdi name and have the extension replacing the character.

would fit good in the existing one I guess :stuck_out_tongue:

1 Like

@makai thank you for your reply above, it was exactly what I was looking for.

I have some minor improvements to make working with the unicode chars slightly easier.

  1. Download the materialdesignicons.com zip file and open “preview.html” in a browser - it is much easier than working with font-viewing software as suggested above.
  2. Text search to find the icons
  3. Click on the char code to copy it to clipboard, eg F0594
  4. Add \U000 in front of the F for use in YAML, eg \U000F0594

i2c:

font:
  - file: 'fonts/materialdesignicons-webfont.ttf'
    id: icon_font
    size: 40
    glyphs:
      - "\U000F0594" # mdi-weather-night
      - "\U000F0599" # mdi-weather-sunny

display:
  - id: oled
    platform: ssd1306_i2c
    model: SSD1306 64x48
    address: 0x3C
    lambda: |-
      it.print(32, 24, id(icon_font), TextAlign::CENTER, "\U000F0599");
13 Likes

Awesome thanks! In that case it is not even needed to download the font: just navigate to http://cdn.materialdesignicons.com/5.4.55/ to look at them.

This Python script:

from urllib.request import urlopen
import json
import re

url = urlopen("https://raw.githubusercontent.com/Templarian/MaterialDesign/master/meta.json")
meta = [(i['name'], i['codepoint']) for i in json.loads(url.read()) if re.search('^weather-', i['name'])]

print('''---
esphome:
  # ...
  includes:
    - weather_icon_map.h

# ...

font:
  - file: fonts/materialdesignicons-webfont.ttf
    id: ...
    size: ...
    glyphs:''')

for name, codepoint in meta:
    print('      - "\\U000%s" # %s' % (codepoint, name))

with open('weather_icon_map.h', 'w') as h:
    h.write('#include <map>\nstd::map<std::string, std::string> weather_icon_map\n')
    h.write('  {\n')
    for name, codepoint in meta:
        h.write('    {"%s", "\\U000%s"},\n' % (name.replace('weather-', ''), codepoint))
    h.write('  };')

will output:

font:
  - file: fonts/materialdesignicons-webfont.ttf
    id: icon_font
    size: 48
    glyphs:
      - "\U000F0590" # weather-cloudy
      - "\U000F0F2F" # weather-cloudy-alert
      - "\U000F0E6E" # weather-cloudy-arrow-right
      - "\U000F0591" # weather-fog
      - "\U000F0592" # weather-hail
      - "\U000F0F30" # weather-hazy
      - "\U000F0898" # weather-hurricane
      - "\U000F0593" # weather-lightning
      - "\U000F067E" # weather-lightning-rainy
      - "\U000F0594" # weather-night
      - "\U000F0F31" # weather-night-partly-cloudy
      - "\U000F0595" # weather-partly-cloudy
      - "\U000F0F32" # weather-partly-lightning
      - "\U000F0F33" # weather-partly-rainy
      - "\U000F0F34" # weather-partly-snowy
      - "\U000F0F35" # weather-partly-snowy-rainy
      - "\U000F0596" # weather-pouring
      - "\U000F0597" # weather-rainy
      - "\U000F0598" # weather-snowy
      - "\U000F0F36" # weather-snowy-heavy
      - "\U000F067F" # weather-snowy-rainy
      - "\U000F0599" # weather-sunny
      - "\U000F0F37" # weather-sunny-alert
      - "\U000F14E4" # weather-sunny-off
      - "\U000F059A" # weather-sunset
      - "\U000F059B" # weather-sunset-down
      - "\U000F059C" # weather-sunset-up
      - "\U000F0F38" # weather-tornado
      - "\U000F059D" # weather-windy
      - "\U000F059E" # weather-windy-variant

and:

weather_icon_map.h

#include <map>
std::map<std::string, std::string> weather_icon_map
  {
    {"cloudy", "\U000F0590"},
    {"cloudy-alert", "\U000F0F2F"},
    {"cloudy-arrow-right", "\U000F0E6E"},
    {"fog", "\U000F0591"},
    {"hail", "\U000F0592"},
    {"hazy", "\U000F0F30"},
    {"hurricane", "\U000F0898"},
    {"lightning", "\U000F0593"},
    {"lightning-rainy", "\U000F067E"},
    {"night", "\U000F0594"},
    {"night-partly-cloudy", "\U000F0F31"},
    {"partly-cloudy", "\U000F0595"},
    {"partly-lightning", "\U000F0F32"},
    {"partly-rainy", "\U000F0F33"},
    {"partly-snowy", "\U000F0F34"},
    {"partly-snowy-rainy", "\U000F0F35"},
    {"pouring", "\U000F0596"},
    {"rainy", "\U000F0597"},
    {"snowy", "\U000F0598"},
    {"snowy-heavy", "\U000F0F36"},
    {"snowy-rainy", "\U000F067F"},
    {"sunny", "\U000F0599"},
    {"sunny-alert", "\U000F0F37"},
    {"sunny-off", "\U000F14E4"},
    {"sunset", "\U000F059A"},
    {"sunset-down", "\U000F059B"},
    {"sunset-up", "\U000F059C"},
    {"tornado", "\U000F0F38"},
    {"windy", "\U000F059D"},
    {"windy-variant", "\U000F059E"},
  };
6 Likes

I cannot access to the link. Is it down?
Can s.b. please send me a working link or the font?

Best regards,
Stefan

Thank you for your icon list.
For those of you using weather forecast from met.no, delivered by the Norwegian Meteorological Institute, and also needs their native text weather in Norwegian; her is for you. The material Design weather icons don’t have all the icons/types of weather that Norwegian Meteorological Institute use. Here is the complete list, that uses the icon number from met.no.

      yr_symbol_text:
        friendly_name: "Akkurat nå:"
        value_template: >-
          {% if states.sensor.yr_symbol.state | int==1%}Klart
          {% elif states.sensor.yr_symbol.state | int==2%}Lettskyet
          {% elif states.sensor.yr_symbol.state | int==3%}Delvis skyet
          {% elif states.sensor.yr_symbol.state | int==4%}Skyet
          {% elif states.sensor.yr_symbol.state | int==5%}Regnbyger
          {% elif states.sensor.yr_symbol.state | int==6%}Regnbyger med torden
          {% elif states.sensor.yr_symbol.state | int==7%}Sluddbyger
          {% elif states.sensor.yr_symbol.state | int==8%}Snøbyger
          {% elif states.sensor.yr_symbol.state | int==9%}Regn
          {% elif states.sensor.yr_symbol.state | int==10%}Kraftig regn
          {% elif states.sensor.yr_symbol.state | int==11%}Kraftig regn og torden
          {% elif states.sensor.yr_symbol.state | int==12%}Sludd
          {% elif states.sensor.yr_symbol.state | int==13%}Snø
          {% elif states.sensor.yr_symbol.state | int==14%}Snø og torden
          {% elif states.sensor.yr_symbol.state | int==15%}Tåke
          {% elif states.sensor.yr_symbol.state | int==20%}Sluddbyger og torden
          {% elif states.sensor.yr_symbol.state | int==21%}Snøbyger og torden
          {% elif states.sensor.yr_symbol.state | int==22%}Regn og torden
          {% elif states.sensor.yr_symbol.state | int==23%}Sludd og torden
          {% elif states.sensor.yr_symbol.state | int==24%}Lette regbyger og torden
          {% elif states.sensor.yr_symbol.state | int==25%}Kraftige regnbyger og torden
          {% elif states.sensor.yr_symbol.state | int==26%}Lette sluddbyger og torden
          {% elif states.sensor.yr_symbol.state | int==27%}Kraftige sluddbyger og torden
          {% elif states.sensor.yr_symbol.state | int==28%}Lette snøbyger og torden
          {% elif states.sensor.yr_symbol.state | int==29%}Kraftige snøbyger og torden
          {% elif states.sensor.yr_symbol.state | int==30%}Lett regn og torden
          {% elif states.sensor.yr_symbol.state | int==31%}Lettt sludd og torden
          {% elif states.sensor.yr_symbol.state | int==32%}Kraftig sludd og torden
          {% elif states.sensor.yr_symbol.state | int==33%}Lett snø og torden
          {% elif states.sensor.yr_symbol.state | int==34%}Kraftig snø og torden
          {% elif states.sensor.yr_symbol.state | int==40%}Lette regnbyger
          {% elif states.sensor.yr_symbol.state | int==41%}Kraftige regnbyger
          {% elif states.sensor.yr_symbol.state | int==42%}Lette sluddbyger
          {% elif states.sensor.yr_symbol.state | int==43%}Kraftige sluddbyger
          {% elif states.sensor.yr_symbol.state | int==44%}Lette snøbyger
          {% elif states.sensor.yr_symbol.state | int==45%}Kraftige snøbyger
          {% elif states.sensor.yr_symbol.state | int==46%}Lett regn
          {% elif states.sensor.yr_symbol.state | int==47%}Lett sludd
          {% elif states.sensor.yr_symbol.state | int==48%}Kraftig sludd
          {% elif states.sensor.yr_symbol.state | int==49%}Lett snø
          {% elif states.sensor.yr_symbol.state | int==50%}Kraftig snø
          {% endif %}
        entity_picture_template: >-
          {% if is_state('sun.sun', 'above_horizon') %}
            //api.met.no/weatherapi/weathericon/1.1/?symbol={{states.sensor.yr_symbol.state}};is_night=0;content_type=image/png
          {% else %}
            //api.met.no/weatherapi/weathericon/1.1/?symbol={{states.sensor.yr_symbol.state}};is_night=1;content_type=image/png
          {% endif %}

Here is the ESPHome display: definition I use, following by the font:definitions.

display:
  ...
    lambda: |-
      if (id(current).has_state()) {
        std::map<std::string, std::string> weather_icon_map
          {
            {"Klart", "\U000F0599"},
            {"Lettskyet", "\U000F0595"},       // Lettskyet og delvis skyet deler ikon
            {"Delvis skyet", "\U000F0595"},
            {"Skyet", "\U000F0590"},
            {"Regnbyger", "\U000F0F33"},
            {"Regnbyger med torden", "\U000F0F32"},
            {"Sluddbyger", "\U000F067F"},
            {"Snøbyger", "\U000F0F36"},
            {"Regn", "\U000F0597"},
            {"Kraftig regn", "\U000F0596"},
            {"Kraftig regn og torden", "\U000F067E"},
            {"Sludd", "\U000F067F"},
            {"Snø", "\U000F0598"},
            {"Snø og torden", "\U000F0598"},
            {"Tåke", "\U000F0591"},
            {"Regn og torden", "\U000F067E"},
            {"Torden", "\U000F0593"},
            {"Lette snøbyger", "\U000F0F34"},
          };
            it.printf(0, 50, id(icon_font_22), TextAlign::BASELINE_LEFT, weather_icon_map[id(current).state.c_str()].c_str());
      }

2 Likes

Hello,

i find this integration very interesting and I was trying to adapt it to Hassio Alarm Panel.

Could you please suggest me the right way to let the display show an icon for each state of the alarm panel?

Calling the sensor

text_sensor:
  - platform: homeassistant
    entity_id: alarm_control_panel.alarm
    name: "Alarm State"
    id: alarm_state

I loaded the necessary fonts

  - file: 'common/fonts/materialdesignicons-webfont.ttf'
    id: icon_font
    size: 36
    glyphs: [
      "\U000F078F", # mdi-alarm-light
      "\U000F0BEA", # mdi-alarm-light-outline
      "\U000F0237", # mdi-fingerprint
      "\U000F0EB1", # mdi-fingerprint-off
      "\U000F0498", # mdi-shield                 armed_away
      "\U000F0499", # mdi-shield-outline
      "\U000F088F", # mdi-shield-account         armed_home
      "\U000F0A12", # mdi-shield-account-outline
      "\U000F0ECD", # mdi-shield-alert-outline
      "\U000F0565", # mdi-shield-check        pending
      "\U000F0CC8", # mdi-shield-check-outline
      "\U000F0780", # mdi-shield-half-full        armed_night
      "\U000F0BC4", # mdi-shield-key              arming
      "\U000F0BC5", # mdi-shield-key-outline
      "\U000F099E", # mdi-shield-off            disarmed
      "\U000F033F", # mdi-lock-open            pending
      "\U000F0340", # mdi-lock-open-outline    disarming
      "\U000F139C", # mdi-lock-check           triggered
      "\U000F0FC5", # mdi-location-exit       armed_custom_bypass
      "\U000F009E", # mdi-bell-ring         bell
      "\U000F009F", # mdi-bell-ring-outline
      ]

these are supposed to be the different states for each of them I would like to relate an icon but I can’t figure how to show them.

    if (id(alarm_control_panel.alarm).has_state()) {
          {
              {"disarmed", "\U000F099E"},
             {"armed_home", "\U000F088F"},
             {"armed_away", "\U000F0498"},
             {"armed_night", "\U000F0780"},
             {"armed_custom_bypass", "\U000F0FC5"},
             {"pending", "\U000F0565"},
             {"arming", "\U000F0BC4"},
             {"disarming", "\U000F0340"},
             {"triggered", "\U000F139C"},
           };
             it.printf(64, 32, id(icon_font), TextAlign::CENTER, alarm_control_panel.alarm[id(current).state.c_str()].c_str());
      }

any idea? thank you in advance

Hi,
I found this old thread with a lot of useful information about how to show icons in a display but when trying to implement it, I am getting an error. Let me explain:
I have created a text sensor in HA witn values such us “\U000F0599” that change depending on the weather condition (sunny, cloudy…).
I define the font and import the glyphs as explained above and, in fact, I can see the icon in the display with an instruction like this:

it.printf(0, 70, id(icon_font_2_48), TextAlign::LEFT, "\U000F0599");

But when I try to use the text sensor value to change it dinamically with this instruction, I only get a white rectangle:

it.printf(0, 70, id(icon_font_2_48), TextAlign::LEFT, id(my_text_sensor_from_HA).state.c_str());

Checking the log, the error I get looks like it is trying to render within the font each character of the string instead of the string itself.

16:26:05	[W]	[display:176] Encountered character without representation in font: '"'
16:26:05	[W]	[display:176] Encountered character without representation in font: '\'
16:26:05	[W]	[display:176] Encountered character without representation in font: 'U'
16:26:05	[W]	[display:176] Encountered character without representation in font: '0'
...

I would appreciate any advise here.

Thanks and best regards

1 Like

Im no expert by any means, but you need to add glyphs

For eg

  - file: 'fonts/GothamRnd-Bold.ttf'
    id: font_small_bold
    size: 20
    glyphs: 
      ['&', '@', '!', ',', '.', '"', '%', '(', ')', '+', '-', '_', ':', '°', '0',
       '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E',
       'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
       'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', 'a', 'b', 'c', 'd', 'e', 'f',
       'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
       'u', 'v', 'w', 'x', 'y', 'z', '/','[', ']',"'"]

Basically is missing characters

1 Like

Thanks for you’re code!

One question though, I get this

/config/esphome/to-do.yaml:212:15: error: reference to 'time' is ambiguous

How are you doing time?

Thanks

EDIT

Got a step further, but now more lost LOL

/config/esphome/to-do.yaml:212:36: error: ISO C++ forbids comparison between pointer and integer [-fpermissive]
           if (homeassistant_time < 1900) {
                                    ^~~~

And a little further LOL, but I guess it doesn’t like the output :frowning:

error: no match for 'operator<' (operand types are 'esphome::time::ESPTime' and 'int')

Check my full code from here: Air Quality Sensors + E-Ink Display using ESPHome

Thank you for this post!!!
Exactly the process helped me.

You can also use this without having to find the unicode values for icons:

image:
  - file: mdi:alert-outline
    id: alert
    resize: 80x80

    • Material Design Icons: Specify the Material Design Icon id in the format mdi:icon-name, and that icon will automatically be downloaded and added to the configuration.
5 Likes

Got this working great, but is it possible to change the colour of the icon?

1 Like

yes was it possible to change icon color ?