Skip to content

Instantly share code, notes, and snippets.

@cnorick
Last active December 8, 2023 21:31
Show Gist options
  • Save cnorick/1ad3d61e7e517fb05e1972908b6b607e to your computer and use it in GitHub Desktop.
Save cnorick/1ad3d61e7e517fb05e1972908b6b607e to your computer and use it in GitHub Desktop.
ESPHome -- Scroll LCD Display Lines
substitutions:
lcd_width: '16'
lcd_height: '2'
scroll_speed: 1s
line_1: 'Long line that we want to scroll'
line_2: 'Another long line that does not fit on the screen'
display:
- platform: lcd_gpio
dimensions: ${lcd_width}x${lcd_height}
data_pins:
- D0
- D1
- D2
- D3
enable_pin: D6
rs_pin: D5
id: lcd
update_interval: $scroll_speed
lambda: |-
static int p1 = 0;
static int p2 = 0;
// These lines could instead come from something like a text sensor.
char* line1 = "$line_1";
int length1 = strlen(line1);
if (length1 > $lcd_width) length1 = $lcd_width;
const char* line2 = "$line_2";
int length2 = strlen(line2);
if (length2 > $lcd_width) length2 = $lcd_width;
int spacesLength = length1 >= $lcd_width ? 0 : $lcd_width - length1 + 1;
char spaces[spacesLength];
for (int i = 0; i < spacesLength - 1; i++) spaces[i] = ' ';
spaces[spacesLength - 1] = '\0';
it.printf("%.*s%s%.*s", length1, line1 + p1, spaces, length2, line2 + p2);
p1++;
if(p1 > (int)strlen(line1) - $lcd_width) {
p1 = 0;
}
p2++;
if(p2 > (int)strlen(line2) - $lcd_width) {
p2 = 0;
}
@cnorick
Copy link
Author

cnorick commented Feb 3, 2023

Hey @steveisaguy, here is my whole configuration where I use the scrolling LCD. I haven't used this device in a while, so there's a chance it will no longer work after some of the new ESPHome updates. Good luck with it!

substitutions:
  lcd_width: '16'
  lcd_height: '2'
  scroll_speed: 1s

esphome:
  name: meeting-status-board
  platform: ESP8266
  board: nodemcuv2

# Enable logging
logger:
  level: DEBUG

# Enable Home Assistant API
api:

ota:
  password: !secret ota_password

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Meeting-Status-Board"
    password: !secret ap_password

captive_portal:

text_sensor:
  - platform: homeassistant
    id: meeting_title
    entity_id: calendar.work
    attribute: message
    name: "Meeting Title"
    disabled_by_default: true
  - platform: homeassistant
    id: meeting_start
    entity_id: calendar.work
    attribute: start_time
    name: "Meeting Start Time"
    disabled_by_default: true
  - platform: homeassistant
    id: meeting_end
    entity_id: calendar.work
    attribute: end_time
    name: "Meeting End Time"
    disabled_by_default: true
  - platform: template
    name: "Current Light"
    lambda: |-
      if (id(in_meeting).state) {
        return {"red"};
      }
      else if (id(meeting_started).state) {
        return {"yellow"};
      }
      else {
        return {"green"};
      }
    update_interval: 5s
    id: current_light
    disabled_by_default: true
    on_value:
      then:
        - switch.turn_off: green_light
        - switch.turn_off: yellow_light
        - switch.turn_off: red_light
        - if:
            condition:
              binary_sensor.is_on: in_meeting
            then:
              - switch.turn_on: red_light
            else:
              - if:
                  condition:
                    binary_sensor.is_on: meeting_started
                  then:
                    - switch.turn_on: yellow_light
                  else:
                    - switch.turn_on: green_light
    
binary_sensor:
  - platform: homeassistant
    id: meeting_started
    entity_id: calendar.work
    name: "Meeting Started"
    disabled_by_default: true
  - platform: homeassistant
    id: in_meeting
    entity_id: binary_sensor.in_meeting
    name: "In Meeting"
    disabled_by_default: true

switch:
  - platform: gpio
    pin: D7
    name: "Green Light"
    internal: true
    id: green_light
  - platform: gpio
    pin: D8
    name: "Yellow Light"
    internal: true
    id: yellow_light
  - platform: gpio
    pin: 9
    name: "Red Light"
    internal: true
    id: red_light

display:
  - platform: lcd_gpio
    dimensions: ${lcd_width}x${lcd_height}
    data_pins:
      - D0
      - D1
      - D2
      - D3
    enable_pin: D6
    rs_pin: D5
    id: lcd
    update_interval: $scroll_speed
    lambda: |-
      static int p1 = 0;
      static int p2 = 0;
      
      char line1[$lcd_width];
      char startString[$lcd_width/2];
      char endString[$lcd_width/2];
      struct tm start;
      memset(&start, 0, sizeof(tm));
      struct tm end;
      memset(&end, 0, sizeof(tm));
      strptime(id(meeting_start).state.c_str(), "%Y-%m-%d %H:%M:%S", &start);
      strftime(startString, sizeof(startString), "%I:%M", &start);
      
      strptime(id(meeting_end).state.c_str(), "%Y-%m-%d %H:%M:%S", &end);
      strftime(endString, sizeof(endString), "%I:%M", &end);
      sprintf(line1, "%s - %s", startString, endString);
      
      int length1 = strlen(line1);
            
      const char* line2 = id(meeting_title).state.c_str();
      int length2 = strlen(line2);
      if (length2 > $lcd_width) length2 = $lcd_width;
      
      int spacesLength = length1 >= $lcd_width ? 0 : $lcd_width - length1 + 1;
      char spaces[spacesLength];
      for (int i = 0; i < spacesLength - 1; i++) spaces[i] = ' ';
      spaces[spacesLength - 1] = '\0';
      
      it.printf("%.*s%s%.*s", length1, line1 + p1, spaces, length2, line2 + p2);

      p1++;
      if(p1 > (int)strlen(line1) - $lcd_width) {
        p1 = 0;
      }
      p2++;
      if(p2 > (int)strlen(line2) - $lcd_width) {
        p2 = 0;
      }

@djansen1987
Copy link

Hey @steveisaguy, here is my whole configuration where I use the scrolling LCD. I haven't used this device in a while, so there's a chance it will no longer work after some of the new ESPHome updates. Good luck with it!

substitutions:
  lcd_width: '16'
  lcd_height: '2'
  scroll_speed: 1s

esphome:
  name: meeting-status-board
  platform: ESP8266
  board: nodemcuv2

# Enable logging
logger:
  level: DEBUG

# Enable Home Assistant API
api:

ota:
  password: !secret ota_password

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Meeting-Status-Board"
    password: !secret ap_password

captive_portal:

text_sensor:
  - platform: homeassistant
    id: meeting_title
    entity_id: calendar.work
    attribute: message
    name: "Meeting Title"
    disabled_by_default: true
  - platform: homeassistant
    id: meeting_start
    entity_id: calendar.work
    attribute: start_time
    name: "Meeting Start Time"
    disabled_by_default: true
  - platform: homeassistant
    id: meeting_end
    entity_id: calendar.work
    attribute: end_time
    name: "Meeting End Time"
    disabled_by_default: true
  - platform: template
    name: "Current Light"
    lambda: |-
      if (id(in_meeting).state) {
        return {"red"};
      }
      else if (id(meeting_started).state) {
        return {"yellow"};
      }
      else {
        return {"green"};
      }
    update_interval: 5s
    id: current_light
    disabled_by_default: true
    on_value:
      then:
        - switch.turn_off: green_light
        - switch.turn_off: yellow_light
        - switch.turn_off: red_light
        - if:
            condition:
              binary_sensor.is_on: in_meeting
            then:
              - switch.turn_on: red_light
            else:
              - if:
                  condition:
                    binary_sensor.is_on: meeting_started
                  then:
                    - switch.turn_on: yellow_light
                  else:
                    - switch.turn_on: green_light
    
binary_sensor:
  - platform: homeassistant
    id: meeting_started
    entity_id: calendar.work
    name: "Meeting Started"
    disabled_by_default: true
  - platform: homeassistant
    id: in_meeting
    entity_id: binary_sensor.in_meeting
    name: "In Meeting"
    disabled_by_default: true

switch:
  - platform: gpio
    pin: D7
    name: "Green Light"
    internal: true
    id: green_light
  - platform: gpio
    pin: D8
    name: "Yellow Light"
    internal: true
    id: yellow_light
  - platform: gpio
    pin: 9
    name: "Red Light"
    internal: true
    id: red_light

display:
  - platform: lcd_gpio
    dimensions: ${lcd_width}x${lcd_height}
    data_pins:
      - D0
      - D1
      - D2
      - D3
    enable_pin: D6
    rs_pin: D5
    id: lcd
    update_interval: $scroll_speed
    lambda: |-
      static int p1 = 0;
      static int p2 = 0;
      
      char line1[$lcd_width];
      char startString[$lcd_width/2];
      char endString[$lcd_width/2];
      struct tm start;
      memset(&start, 0, sizeof(tm));
      struct tm end;
      memset(&end, 0, sizeof(tm));
      strptime(id(meeting_start).state.c_str(), "%Y-%m-%d %H:%M:%S", &start);
      strftime(startString, sizeof(startString), "%I:%M", &start);
      
      strptime(id(meeting_end).state.c_str(), "%Y-%m-%d %H:%M:%S", &end);
      strftime(endString, sizeof(endString), "%I:%M", &end);
      sprintf(line1, "%s - %s", startString, endString);
      
      int length1 = strlen(line1);
            
      const char* line2 = id(meeting_title).state.c_str();
      int length2 = strlen(line2);
      if (length2 > $lcd_width) length2 = $lcd_width;
      
      int spacesLength = length1 >= $lcd_width ? 0 : $lcd_width - length1 + 1;
      char spaces[spacesLength];
      for (int i = 0; i < spacesLength - 1; i++) spaces[i] = ' ';
      spaces[spacesLength - 1] = '\0';
      
      it.printf("%.*s%s%.*s", length1, line1 + p1, spaces, length2, line2 + p2);

      p1++;
      if(p1 > (int)strlen(line1) - $lcd_width) {
        p1 = 0;
      }
      p2++;
      if(p2 > (int)strlen(line2) - $lcd_width) {
        p2 = 0;
      }

This looks like a cool project, do you have a photo on how the project looks. Seems you used it for a meeting room display

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment