7 Segment LED clock using sn74hc595 shift registers

I’m trying to build a 4 * 7 Segment LED Clock using four sn74hc595 shift registers. The below code works and I can drive the individual segments of my first 7-segment display from the UI (I’ve only configured the first 8 switches, I know I have to create the others as well). But clearly, that’s not a clock :-).

I am comfortable writing and want to use Lambda to create the rest of the clock to switch on the relevant segments but I’m not sure in which type of Yaml-ESPBlock to embed the code in. All the examples I have seen so far use a specific platform, for example, this one uses the neopixelbus platform. But I’m not sure what I should use as I just want to (regularly) run some code that sets the relevant segments.

I hope that question makes sense and if anyone could point me to a simple example I would appreciate it.

sn74hc595:  
  - id: 'sn74hc595_hub'
    data_pin:   D4  #  D5 - SD Pin
    clock_pin:  D2  #  D8 - SH_CP Pin
    latch_pin:  D3  #  D7 - ST_CP Pin
    # oe_pin: D6
    sr_count: 4
    
# Individual outputs

switch:
  - platform: gpio
    name: ${device_name}_p0
    id: ${device_name}_p0
    pin:
      sn74hc595: 'sn74hc595_hub'
      number: 0
      inverted: True
  - platform: gpio
    name: ${device_name}_p1
    id: ${device_name}_p1
    pin:
      sn74hc595: 'sn74hc595_hub'
      number: 1
      inverted: True
  - platform: gpio
    name: ${device_name}_p2
    id: ${device_name}_p2
    pin:
      sn74hc595: 'sn74hc595_hub'
      number: 2
      inverted: True
  - platform: gpio
    name: ${device_name}_p3
    id: ${device_name}_p3
    pin:
      sn74hc595: 'sn74hc595_hub'
      number: 3
      inverted: True
  - platform: gpio
    name: ${device_name}_p4
    id: ${device_name}_p4
    pin:
      sn74hc595: 'sn74hc595_hub'
      number: 4
      inverted: True
  - platform: gpio
    name: ${device_name}_p5
    id: ${device_name}_p5
    pin:
      sn74hc595: 'sn74hc595_hub'
      number: 5
      inverted: True
  - platform: gpio
    name: ${device_name}_p6
    id: ${device_name}_p6
    pin:
      sn74hc595: 'sn74hc595_hub'
      number: 6
      inverted: True
  - platform: gpio
    name: ${device_name}_p7
    id: ${device_name}_p7
    pin:
      sn74hc595: 'sn74hc595_hub'
      number: 7
      inverted: True

  - platform: template
    name: ${device_name}_on
    lambda: |-
      return {};
    turn_on_action:
      - switch.turn_on: ${device_name}_p0
      - switch.turn_on: ${device_name}_p1
      - switch.turn_on: ${device_name}_p2
      - switch.turn_on: ${device_name}_p3
      - switch.turn_on: ${device_name}_p4
      - switch.turn_on: ${device_name}_p5
      - switch.turn_on: ${device_name}_p6
      - switch.turn_on: ${device_name}_p7

Ok, it sounds like you want to use a Lambda function in your Home Assistant configuration to drive the segments of your 7-segment LED clock. In order to do this, you can use the lambda: platform in your Home Assistant configuration.

Here is an example of how you could use the lambda: platform in your configuration to drive the segments of your 7-segment LED clock:

# Define the Lambda function that will drive the segments of your 7-segment LED clock
lambda:
  - name: drive_7segment_led_clock
    sequence:
      - service: switch.turn_on
        data:
          entity_id: ${device_name}_p0
          # Set the relevant switch states here to turn on the desired segments of the 7-segment LED clock
          # For example, to turn on the top segment, you could set the state of ${device_name}_p0 to ON

You can then call this Lambda function at regular intervals using the time: platform in your Home Assistant configuration, as shown in the following example:

# Call the Lambda function at regular intervals to update the segments of the 7-segment LED clock
time:
  - platform: time_pattern
    minutes: "/1"
    seconds: 0
    lambda: drive_7segment_led_clock

This configuration will call the drive_7segment_led_clock Lambda function every minute, which will update the segments of your 7-segment LED clock.

You can modify the time pattern to suit your needs and to update the clock at the desired frequency.

Thanks @bastero - I think that’s the solution I’m looking for. I will try it and report back!

I got it to work and here’s the code. It’s rather pointless having a clock like this but I enjoyed building it. Any questions - just ask:

substitutions:
  device_name: led_segment_clock
  
esphome:
  #name: led-segment-clock
  name: ${device_name}
  platform: ESP8266
  board: d1_mini_pro

# Enable logging
logger:

# Enable Home Assistant API
api:

ota:

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  manual_ip:
    static_ip: 192.168.1.24
    gateway: 192.168.1.254
    subnet: 255.255.255.0


  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Led-Segment-Clock"
    password: "XWDVKsyPNfF5"

captive_portal:

#   SN74HC595 Shift Register Use with ESPHome
#   https://esphome.io/components/sn74hc595.html
#   
#   I have 4 SN74HC595 shift registers connected to a Wemos D1 Mini Pro and every shift register is
#   connected to a 7 Segment, Common Anode LED display. The Pin connections are below, only other pin is D5 on the Wemos which I connected
#   to the dot of the second Digit. I could have used the shift register for that as well but I only realised I wanted to do that 
#   after I finished soldering.
#

sn74hc595:  
  - id: 'sn74hc595_hub'
    data_pin:   D4  #  SD Pin
    clock_pin:  D2  #  SH_CP Pin
    latch_pin:  D3  #  ST_CP Pin
    # oe_pin: D6
    sr_count: 4
    
# Individual outputs

switch:
  - platform: gpio
    name: ${device_name}_blink
    id: ${device_name}_blink
    pin: D5
  - platform: gpio
    name: ${device_name}_p0
    id: ${device_name}_p0
    pin:
      sn74hc595: 'sn74hc595_hub'
      number: 0
      inverted: True
  - platform: gpio
    name: ${device_name}_p1
    id: ${device_name}_p1
    pin:
      sn74hc595: 'sn74hc595_hub'
      number: 1
      inverted: True
  - platform: gpio
    name: ${device_name}_p2
    id: ${device_name}_p2
    pin:
      sn74hc595: 'sn74hc595_hub'
      number: 2
      inverted: True
  - platform: gpio
    name: ${device_name}_p3
    id: ${device_name}_p3
    pin:
      sn74hc595: 'sn74hc595_hub'
      number: 3
      inverted: True
  - platform: gpio
    name: ${device_name}_p4
    id: ${device_name}_p4
    pin:
      sn74hc595: 'sn74hc595_hub'
      number: 4
      inverted: True
  - platform: gpio
    name: ${device_name}_p5
    id: ${device_name}_p5
    pin:
      sn74hc595: 'sn74hc595_hub'
      number: 5
      inverted: True
  - platform: gpio
    name: ${device_name}_p6
    id: ${device_name}_p6
    pin:
      sn74hc595: 'sn74hc595_hub'
      number: 6
      inverted: True
  - platform: gpio
    name: ${device_name}_p7
    id: ${device_name}_p7
    pin:
      sn74hc595: 'sn74hc595_hub'
      number: 7
      inverted: True
# LED 2
  - platform: gpio
    name: ${device_name}_p8
    id: ${device_name}_p8
    pin:
      sn74hc595: 'sn74hc595_hub'
      number: 8
      inverted: True
  - platform: gpio
    name: ${device_name}_p9
    id: ${device_name}_p9
    pin:
      sn74hc595: 'sn74hc595_hub'
      number: 9
      inverted: True
  - platform: gpio
    name: ${device_name}_p10
    id: ${device_name}_p10
    pin:
      sn74hc595: 'sn74hc595_hub'
      number: 10
      inverted: True
  - platform: gpio
    name: ${device_name}_p11
    id: ${device_name}_p11
    pin:
      sn74hc595: 'sn74hc595_hub'
      number: 11
      inverted: True
  - platform: gpio
    name: ${device_name}_p12
    id: ${device_name}_p12
    pin:
      sn74hc595: 'sn74hc595_hub'
      number: 12
      inverted: True
  - platform: gpio
    name: ${device_name}_p13
    id: ${device_name}_p13
    pin:
      sn74hc595: 'sn74hc595_hub'
      number: 13
      inverted: True
  - platform: gpio
    name: ${device_name}_p14
    id: ${device_name}_p14
    pin:
      sn74hc595: 'sn74hc595_hub'
      number: 14
      inverted: True
  - platform: gpio
    name: ${device_name}_p15
    id: ${device_name}_p15
    pin:
      sn74hc595: 'sn74hc595_hub'
      number: 15
      inverted: True
# LED 3
  - platform: gpio
    name: ${device_name}_p16
    id: ${device_name}_p16
    pin:
      sn74hc595: 'sn74hc595_hub'
      number: 16
      inverted: True
  - platform: gpio
    name: ${device_name}_p17
    id: ${device_name}_p17
    pin:
      sn74hc595: 'sn74hc595_hub'
      number: 17
      inverted: True
  - platform: gpio
    name: ${device_name}_p18
    id: ${device_name}_p18
    pin:
      sn74hc595: 'sn74hc595_hub'
      number: 18
      inverted: True
  - platform: gpio
    name: ${device_name}_p19
    id: ${device_name}_p19
    pin:
      sn74hc595: 'sn74hc595_hub'
      number: 19
      inverted: True
  - platform: gpio
    name: ${device_name}_p20
    id: ${device_name}_p20
    pin:
      sn74hc595: 'sn74hc595_hub'
      number: 20
      inverted: True
  - platform: gpio
    name: ${device_name}_p21
    id: ${device_name}_p21
    pin:
      sn74hc595: 'sn74hc595_hub'
      number: 21
      inverted: True
  - platform: gpio
    name: ${device_name}_p22
    id: ${device_name}_p22
    pin:
      sn74hc595: 'sn74hc595_hub'
      number: 22
      inverted: True
  - platform: gpio
    name: ${device_name}_p23
    id: ${device_name}_p23
    pin:
      sn74hc595: 'sn74hc595_hub'
      number: 23
      inverted: True
# LED 4
  - platform: gpio
    name: ${device_name}_p24
    id: ${device_name}_p24
    pin:
      sn74hc595: 'sn74hc595_hub'
      number: 24
      inverted: True
  - platform: gpio
    name: ${device_name}_p25
    id: ${device_name}_p25
    pin:
      sn74hc595: 'sn74hc595_hub'
      number: 25
      inverted: True
  - platform: gpio
    name: ${device_name}_p26
    id: ${device_name}_p26
    pin:
      sn74hc595: 'sn74hc595_hub'
      number: 26
      inverted: True
  - platform: gpio
    name: ${device_name}_p27
    id: ${device_name}_p27
    pin:
      sn74hc595: 'sn74hc595_hub'
      number: 27
      inverted: True
  - platform: gpio
    name: ${device_name}_p28
    id: ${device_name}_p28
    pin:
      sn74hc595: 'sn74hc595_hub'
      number: 28
      inverted: True
  - platform: gpio
    name: ${device_name}_p29
    id: ${device_name}_p29
    pin:
      sn74hc595: 'sn74hc595_hub'
      number: 29
      inverted: True
  - platform: gpio
    name: ${device_name}_p30
    id: ${device_name}_p30
    pin:
      sn74hc595: 'sn74hc595_hub'
      number: 30
      inverted: True
  - platform: gpio
    name: ${device_name}_p31
    id: ${device_name}_p31
    pin:
      sn74hc595: 'sn74hc595_hub'
      number: 31
      inverted: True

  - platform: template
    name: ${device_name}_on
    id: ${device_name}_on
    #lambda: |-
    #  return {};
    turn_on_action: 
      lambda: !lambda |- 
        auto timeVar = id(homeassistant_time).now();
        if (!timeVar.is_valid()) {
          return;
        }
        int second_idx  = (int) (timeVar.second);
        
        //  The dot of the second display is connected to GPIO - D5 of my Wemos D1 Mini Pro
        //  Which blinks every second
        
        if ((second_idx % 2) == 0) {
          id(${device_name}_blink).turn_on();
        }
        else {
          id(${device_name}_blink).turn_off();          
        }
        
        int minute_idx  = (int) (timeVar.minute);
        int minute_low  =  minute_idx % 10;
        int minute_high = (minute_idx - minute_low) / 10;
        
        int hour_idx    = (int) (timeVar.hour);
        int hour_low    =  hour_idx % 10;
        int hour_high   = (hour_idx - hour_low) / 10;
        
        // For a common Anode 7 Segment display, these are the voltage you need to set
        // on the individual segments. 
        
        int ledSegments [10][8]{
          {0,1,1,1,1,1,1,0}, // digit 0 // 000$0001 DEC 1
          {0,0,1,1,0,0,0,0}, // digit 1 // 100$1111 DEC 79
          {0,1,1,0,1,1,0,1}, // digit 2 // 001$0010 DEC 18
          {0,1,1,1,1,0,0,1}, // digit 3 // 000$0110 DEC 6
          {0,0,1,1,0,0,1,1}, // digit 4 // 100$1100 DEC 76
          {0,1,0,1,1,0,1,1}, // digit 5 // 010$0100 DEC 36
          {0,1,0,1,1,1,1,1}, // digit 6 // 010$0000 DEC 32
          {0,1,1,1,0,0,0,0}, // digit 7 // 000$1111 DEC 15
          {0,1,1,1,1,1,1,1}, // digit 8 // 000$0000 DEC 0
          {0,1,1,1,1,0,1,1}  // digit 9 // 000$0100 DEC 4
        };        
        
        int ledCounter = 4;     //  Number of LED's hooked up
        int displayDigit = 0;   // The digit we are displaying
        int displaySegment[8];  // A temporary array to store which LEDs we are going to switch on
        for (int i=0;i<ledCounter;i++) {
        
          if (i==0) displayDigit = minute_low;
          if (i==1) displayDigit = minute_high;
          if (i==2) displayDigit = hour_low;
          if (i==3) displayDigit = hour_high;
          
          displaySegment[0] = ledSegments[displayDigit][0];
          displaySegment[1] = ledSegments[displayDigit][1];
          displaySegment[2] = ledSegments[displayDigit][2];
          displaySegment[3] = ledSegments[displayDigit][3];
          displaySegment[4] = ledSegments[displayDigit][4];
          displaySegment[5] = ledSegments[displayDigit][5];
          displaySegment[6] = ledSegments[displayDigit][6];
          displaySegment[7] = ledSegments[displayDigit][7];

          // Set the segments of the first LED (far right, individual minutes)
          if (i==0) {
            if (displaySegment[0]) {
              id(${device_name}_p0).turn_on();
            }
            else {
              id(${device_name}_p0).turn_off();
            }
            if (displaySegment[1]) {
              id(${device_name}_p1).turn_on();
            }
            else {
              id(${device_name}_p1).turn_off();
            }
            if (displaySegment[2]) {
              id(${device_name}_p2).turn_on();
            }
            else {
              id(${device_name}_p2).turn_off();
            }
            if (displaySegment[3]) {
              id(${device_name}_p3).turn_on();
            }
            else {
              id(${device_name}_p3).turn_off();
            }
            if (displaySegment[4]) {
              id(${device_name}_p4).turn_on();
            }
            else {
              id(${device_name}_p4).turn_off();
            }
            if (displaySegment[5]) {
              id(${device_name}_p5).turn_on();
            }
            else {
              id(${device_name}_p5).turn_off();
            }
            if (displaySegment[6]) {
              id(${device_name}_p6).turn_on();
            }
            else {
              id(${device_name}_p6).turn_off();
            }
            if (displaySegment[7]) {
              id(${device_name}_p7).turn_on();
            }
            else {
              id(${device_name}_p7).turn_off();
            }
          }

          // Set the segments of the second LED (Minutes * 10)
          
          if (i==1) {
            if (displaySegment[0]) {
              id(${device_name}_p8).turn_on();
            }
            else {
              id(${device_name}_p8).turn_off();
            }
            if (displaySegment[1]) {
              id(${device_name}_p9).turn_on();
            }
            else {
              id(${device_name}_p9).turn_off();
            }
            if (displaySegment[2]) {
              id(${device_name}_p10).turn_on();
            }
            else {
              id(${device_name}_p10).turn_off();
            }
            if (displaySegment[3]) {
              id(${device_name}_p11).turn_on();
            }
            else {
              id(${device_name}_p11).turn_off();
            }
            if (displaySegment[4]) {
              id(${device_name}_p12).turn_on();
            }
            else {
              id(${device_name}_p12).turn_off();
            }
            if (displaySegment[5]) {
              id(${device_name}_p13).turn_on();
            }
            else {
              id(${device_name}_p13).turn_off();
            }
            if (displaySegment[6]) {
              id(${device_name}_p14).turn_on();
            }
            else {
              id(${device_name}_p14).turn_off();
            }
            if (displaySegment[7]) {
              id(${device_name}_p15).turn_on();
            }
            else {
              id(${device_name}_p15).turn_off();
            }
          }

          // Set the segments of the third LED (Indivdiual Hours)
          
          if (i==2) {
            if (displaySegment[0]) {
              id(${device_name}_p16).turn_on();
            }
            else {
              id(${device_name}_p16).turn_off();
            }
            if (displaySegment[1]) {
              id(${device_name}_p17).turn_on();
            }
            else {
              id(${device_name}_p17).turn_off();
            }
            if (displaySegment[2]) {
              id(${device_name}_p18).turn_on();
            }
            else {
              id(${device_name}_p18).turn_off();
            }
            if (displaySegment[3]) {
              id(${device_name}_p19).turn_on();
            }
            else {
              id(${device_name}_p19).turn_off();
            }
            if (displaySegment[4]) {
              id(${device_name}_p20).turn_on();
            }
            else {
              id(${device_name}_p20).turn_off();
            }
            if (displaySegment[5]) {
              id(${device_name}_p21).turn_on();
            }
            else {
              id(${device_name}_p21).turn_off();
            }
            if (displaySegment[6]) {
              id(${device_name}_p22).turn_on();
            }
            else {
              id(${device_name}_p22).turn_off();
            }
            if (displaySegment[7]) {
              id(${device_name}_p23).turn_on();
            }
            else {
              id(${device_name}_p23).turn_off();
            }
          }

          // Set the segments of the fourth display, Hours * 10
          
          if (i==3) {
            if (displaySegment[0]) {
              id(${device_name}_p24).turn_on();
            }
            else {
              id(${device_name}_p24).turn_off();
            }
            if (displaySegment[1]) {
              id(${device_name}_p25).turn_on();
            }
            else {
              id(${device_name}_p25).turn_off();
            }
            if (displaySegment[2]) {
              id(${device_name}_p26).turn_on();
            }
            else {
              id(${device_name}_p26).turn_off();
            }
            if (displaySegment[3]) {
              id(${device_name}_p27).turn_on();
            }
            else {
              id(${device_name}_p27).turn_off();
            }
            if (displaySegment[4]) {
              id(${device_name}_p28).turn_on();
            }
            else {
              id(${device_name}_p28).turn_off();
            }
            if (displaySegment[5]) {
              id(${device_name}_p29).turn_on();
            }
            else {
              id(${device_name}_p29).turn_off();
            }
            if (displaySegment[6]) {
              id(${device_name}_p30).turn_on();
            }
            else {
              id(${device_name}_p30).turn_off();
            }
            if (displaySegment[7]) {
              id(${device_name}_p31).turn_on();
            }
            else {
              id(${device_name}_p31).turn_off();
            }
          }

        }
        
    
        
# Call the Lambda function at regular intervals to update the segments of the 7-segment LED clock
time:
  - platform: homeassistant
    id: homeassistant_time
    on_time:
      - minutes: /1
        then:
          - switch.turn_on: ${device_name}_on






2 Likes