Scollting text with random phrases and PIR activated - max7219digit - Wemos D1 - ESPHOME

Hi,

I have built a little door sign with a max7219digit matrix display (4 segments) and Wemos D1 controller.

I want to show a random text, every time someone steps in front of the door. The text variables are entered from a HA dashboard.

So far I managed to show one line of text; I am struggeling with two issues:

  1. only show 1 (out of 4 possible) string at a time
  2. have the display active with a timeout.
  3. I can’t get the output value of the photo resistor converted right into a type that the it.intensity method accepts.

about #1: with the code below, the text randomly jumps while scrolling through all possible variables.

about #2: how can I build a timeout function that turns the display off after x seconds once activated. right now, it just stays active as long as someone is standing in front of the sensor.

about #3: what method do I need to use on the id(adc_val).state) in order to cast a decimal ( I suppose) value type? c_str fails with an exception.

Maybe these are all noob questions, however, this is an early journey on HA and ESPhome for me…

Any help or suggestions is appreciated.

TY

this is the code I have:

# https://gist.github.com/debsahu/0ad5e1de664763e84994cc3a4a5d5dc0
# (original source)
esphome:
  name: veneer_display
  platform: ESP8266
  board: d1_mini

wifi:
  networks:
  - ssid: !secret WiFissid
    password: !secret WiFipassword
  power_save_mode: high
  fast_connect: true

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Veneer Display Fallback Hotspot"
    password: !secret WiFipassword
  

web_server:
  port: 80

captive_portal:

# Enable logging
logger:

# Enable Home Assistant API
api:
#  password: !secret esphome_haapi_pass

ota:
  password: !secret espOta


binary_sensor:
  - platform: gpio
    pin: D2
    name: "Door Sensor"
    id: door_sensor
    device_class: motion

time:
  - platform: homeassistant
    id: homeassistant_time

spi:
  clk_pin: D5  # D5 is connected to CLK of MAX7219
  mosi_pin: D7 # D7 is connected to MOSI of MAX7219

display:
  - platform: max7219digit
    cs_pin: D8 # D8 is connected to CS of MAX7219
    num_chips: 4
    intensity: 3
    scroll_speed: 100ms
    update_interval: 100ms
    lambda: |-
      std::string doortxt_1 = id(doortxt1).state.c_str();
      std::string doortxt_2 = id(doortxt2).state.c_str();
      std::string doortxt_3 = id(doortxt3).state.c_str();
      std::string doortxt_4 = id(doortxt4).state.c_str();
      std::string door_txt[4] = {doortxt_1,doortxt_2,doortxt_3,doortxt_4};
      int v1 = rand() % 4 + 1;
      it.printf(0, 0, id(digit_font), TextAlign::TOP_LEFT, "%s", door_txt[v1].c_str());
      it.intensity(atoi(id(adc_val).state));
      it.scroll_left();
      static int coun = 0;
      if (id(door_sensor).state) {
        it.turn_on_off(true);
      } else{
        it.turn_on_off(false);
      }
      
font:
  - file: "Amiko.ttf"
    id: digit_font
    size: 8

text_sensor:
  - platform: wifi_info
    ip_address:
      name: "Veneer Display IP Address"
    ssid:
      name: "Veneer Display Connected SSID"
    bssid:
      name: "Veneer Display Connected BSSID"
  - platform: homeassistant
    name: "Door Txt1"
    id: doortxt1
    entity_id: input_text.door_txt_1

  - platform: homeassistant
    name: "Door Txt2"
    id: doortxt2
    entity_id: input_text.door_txt_2

  - platform: homeassistant
    name: "Door Txt3"
    id: doortxt3
    entity_id: input_text.door_txt_3

  - platform: homeassistant
    name: "Door Txt4"
    id: doortxt4
    entity_id: input_text.door_txt_4
   
  - platform: homeassistant
    name: "HA Brightness"
    id: habri
    entity_id: input_number.veneer_bri
    
sensor:
  - platform: wifi_signal
    name: "Veneer Display WiFi Signal Sensor"
    update_interval: 60s
  - platform: uptime
    name: "Veneer Display Uptime Sensor"
  - platform: adc
    id: adc_val
    pin: A0 # A photoresistor is connected to 3.3V and A0, A0 is connected to GND with 10k resistor
    name: "Veneer Display Brightness"
    update_interval: 10s
    unit_of_measurement: "adc"
    filters:
      - multiply: 3.3
      - calibrate_linear:
          - 0.0 -> 0.0
          - 3.3 -> 15

Since you are working with max7219 and wemos, I think that you have a more elegant and versatile firmware than ESPhome. Please check out this project.

The advanctage of this is that you can send any text through mqtt and also set parameters also. This is highly versatile and easy.

Thanks. While this might be an option and MQTT is interesting for sure, but I am far from getting comfortable with it; and it will take some time until that will happen.

I would rather like to learn and explore ESPHome based (YAML/Lambda) solutions.

1 Like

After allot of trial and error, searching and learning I was able to get a solution together.

I evolved my approach starting with MQTT and then moving to the Home Assistant API. I found MQTT works well with events such as the RSS feed I am displaying and then the API works well for more static data. Some displays allow you to have pages but not the MAX so I came up with something that made it easier to switch the data and format of what was being displayed. I also create a switch which I could control in Home Assistant to turn the display off.

I think there are some good nuggets here that you could leverage. For the timeout function take a look at the delay feature that is available in an action (and script). Leveraging my code as an example, I would call a script that displays the text followed by a delay for some time and then call the script to turn off the display. You can associate an action to your motion sensor.

Since you only have 4 text variations I might consider just having a global variable increment each time you detect motion to decide which text to display. Might be able to use an index to select the text but if that is too hard I would just hardcode it.

esphome:
  name: dendisplay
  platform: ESP8266
  board: d1_mini

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_pswd
  power_save_mode: none
  manual_ip:
    static_ip: !secret dendisplay_ip
    gateway: !secret gateway
    subnet: !secret subnet
  ap:
    ssid: " Display Fallback Hotspot"
    password: !secret esphome_pswd

captive_portal:

logger:

api:
  password: !secret esphome_pswd

ota:
  password: !secret esphome_pswd

web_server:
  port: 80


globals:
  - id: display_page
    type: int
    restore_value: no
    initial_value: '1'

mqtt:
  broker: !secret mqtt_broker
  username: !secret mqtt_user
  password: !secret mqtt_pswd
  discovery: False
  on_message:
   - topic: display/info/feed
     then:
       - script.execute: display_page2
   - topic: display/info/clock
     then:
       - script.execute: display_page1
   - topic: display/info/playing
     then:
       - script.execute: display_page3

script:
  - id: display_page0
    then:
      - globals.set:
          id: display_page
          value: '0'
      - component.update: max7219digitdisplay
  - id: display_page1
    then:
      - if:
          condition:
            switch.is_on: denmax7219digit
          then:
            - globals.set:
                id: display_page
                value: '1'
            - component.update: max7219digitdisplay
  - id: display_page2
    then:
      - if:
          condition:
            switch.is_on: denmax7219digit
          then:
            - globals.set:
                id: display_page
                value: '2'
            - component.update: max7219digitdisplay
  - id: display_page3
    then:
      - if:
          condition:
            switch.is_on: denmax7219digit
          then:
            - globals.set:
                id: display_page
                value: '3'
            - component.update: max7219digitdisplay

spi:
  clk_pin: D5
  mosi_pin: D7

font:
  - file: "pixelmix.ttf"
    id: digit_font8
    size: 8
  - file: "pixelmix.ttf"
    id: digit_font6
    size: 6
    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
    - °
    
    
display:
  - platform: max7219digit
    id: max7219digitdisplay
    cs_pin: D8
    num_chips: 16
    intensity: 0
    update_interval: 100ms
    lambda: |-
      if (id(display_page) == 0) {
        it.turn_on_off(false); 
        } else {
          if (id(display_page) == 1) {
            it.turn_on_off(true); 
            it.strftime(0, 0, id(digit_font8), "%I:%M", id(hass_time).now()); 
            if (id(outside_temp).has_state()) {
              it.printf(129, 0, id(digit_font6), TextAlign::TOP_RIGHT, "%s  %.1f°C", id(weather_state).state.c_str(), id(outside_temp).state);}
            } else {
              if (id(display_page) == 2) {
                 it.turn_on_off(true); 
                 it.printf(0, 0, id(digit_font8), TextAlign::TOP_LEFT, "%s....", id(newsinfo).state.c_str());
                 it.scroll(true, 0, 1, 3000, 1500);
              } else {
                if (id(display_page) == 3) {
                  it.turn_on_off(true); 
                  it.printf(0, 0, id(digit_font8), TextAlign::TOP_LEFT, "%s", id(media_playing).state.c_str());
                  it.scroll(false);
                }
                     }
                   }
               }


time:
  - platform: homeassistant
    id: hass_time
    timezone: EST+5EDT,M3.2.0/2,M11.1.0/2 

sensor:
  - platform: homeassistant
    name: "Outside Temperature"
    id: outside_temp
    entity_id: sensor.rear_porch_temperature_measurement
    internal: True
    on_value:
      then:
        - component.update: max7219digitdisplay

text_sensor:
  - platform: mqtt_subscribe
    name: "News Feed"
    id: newsinfo
    topic: display/info/feed
    internal: true
  - platform: homeassistant
    name: "Weather"
    id: weather_state
    entity_id: weather.toronto_island
    internal: True
  - platform: homeassistant
    name: "Media Playing"
    id: media_playing
    entity_id: sensor.media_player_den_speaker_media_title
    internal: True
#    on_value:
#      then:
#      - lambda: |-
#          if (id(media_playing) == "unknown") {
#            id(display_page)=1;
#          } else {
#            id(display_page)=3;
#          }
#      - component.update: max7219digitdisplay

switch:
  - platform: template
    name: "Den Max7219"
    id: denmax7219digit
    icon: "mdi:clock-digital"
    restore_state: True
    turn_on_action:
      - switch.template.publish:
          id: denmax7219digit
          state: ON
      - script.execute: display_page1        
    turn_off_action:
      - switch.template.publish:
          id: denmax7219digit
          state: OFF
      - script.execute: display_page0 

status_led:
    pin:
      number: GPIO2

3 Likes

thanks.
yes, that looks promising.
I just need some time to review and figure it out. :slight_smile:

Will post my approach once I got somewhere functional.

Hi @VikingBlod and thanks for sharing your ESPHome code.

I’m trying to adapt to my needs and I’m wondering how are you “feeding” the RSS feed via MQTT.
How should this be done?

Thanks

Sorry been busy and haven’t looked at the forums for awhile. My automation is below. You could delete the lines that create the persistent notification., that adds it to the Notification Menu, I was using that during testing.

alias: RSS News Feed
description: ''
trigger:
  - platform: event
    event_type: feedreader
condition: []
action:
  - service: persistent_notification.create
    data:
      title: News Alert!
      message: 'News : {{trigger.event.data.title}}'
      notification_id: '{{ trigger.event.data.title }}'
  - service: mqtt.publish
    data:
      payload_template: 'News : {{trigger.event.data.title}}'
      retain: true
      topic: display/info/feed
  - delay: '00:05:00'
  - service: mqtt.publish
    data:
      payload_template: ''
      retain: true
      topic: display/info/clock
mode: single

My configuration yaml for the feed is here

feedreader:
  urls:
    - https://rss.cbc.ca/lineup/topstories.xml
  scan_interval:
    minutes: 10
  max_entries: 5

Hi VikingBlod,

I want to display the media player info but when i use your config for page 3 i get the following error:

Compiling /data/esp32-s3-psram-lcd/.pioenvs/esp32-s3-psram-lcd/src/main.cpp.o
/config/esphome/esp32-s3-psram-lcd.yaml: In lambda function:
/config/esphome/esp32-s3-psram-lcd.yaml:388:114: error: request for member ‘c_str’ in ‘media_playing->esphome::homeassistant::HomeassistantSensor::.esphome::sensor::Sensor::state’, which is of non-class type ‘float’
it.printf(it.get_width() - 0, 340, id(font_roboto), id(color_white), TextAlign::RIGHT, “%s”, id(media_playing).state.c_str());
^~~~~
*** [/data/esp32-s3-psram-lcd/.pioenvs/esp32-s3-psram-lcd/src/main.cpp.o] Error 1
========================== [FAILED] Took 4.52 seconds ==========================

Can it be that the config is changed after some HA updates?

can you share your recent config?

Kind regards,

Martijn

Hi Martijn,

I made a number of changes to the config moving from MQTT to Service Calls instead. As part of those changes I dropped the media player references as I didn’t use them. So the current one would not be much use. Sorry.

Neil