Set alarm-time with rotary encoder on a Wemos d1mini ESPhome

I would like to use it to set the alarmtime of my wakuplight in HomeAssistant.
I have found a ESPhome project where a rotary-button is used to set volume and pause/play a media_player in Homeassitant:
ESPhome volume button

I’m no programmer, so I’m struggling with the code to get it working the way I would like to use the button:

  • Long press: enter alarm-setting, hour (turn knob → hour up/down)
  • Short press: toggle between alarm hour/minute set (turning the knob → mins up/down)
  • Double press: toggle alarm on/off
  • Long press again: end alarm setting

All I can find is the “input_datetime.set”-example, but have no clue how to change the hour/minutes this way.

> - service: input_datetime.set_datetime
>   target:
>     entity_id: input_datetime.XXX
>   data:
>     time: "05:30:00"

Probably need templating, fiddling with the time:“05:30:00” part, but that’s a bit to advanced and I have no clue how that might look like to get it to work…
I have two types of button/display devices both based on a Wemos D1 mini, one with a 4x64 led-dot matrix and one with a 8x7 segment led and 8 buttons. See attached photo’s.
IMG_3179
IMG_3176
So the idea is to use the rotary encoder (or buttons) to set the alarm-time.
In the UI of HA this is done by typing the desired values in a lovelace-card with input-box:
Schermafbeelding 2021-04-20 om 17 20 13
But I would like to set the alarmtime on the clock itself, by turning and clicking the encoder and/or buttons.
I managed to display time and alarmtime on the device and toggle the alarm on/off, but I struggle to get the clicks and turns converted to increase/decrease of the hours en minutes.
I think I have to fiddle with the data-part in the service: input_datetime.set_datetime, but have no clue how to do this…

1 Like

Did you figure it out?

partly, I can set the alarmtime from the esp to HA, but have to find a way to change the esp time when I adjust the alarmtime from inside HA.

##################################################################
# Wemos D1 mini met MAX7219 4x64 matrix display en rotary button #
# 20211229                                                       #
##################################################################

substitutions:
  name: wekker-8x7
  friendly_name: Wekker slaapkamer
  platform: ESP8266 #ESP32
  board: d1_mini
  #plug_ip: !secret lsc_led_01_ip
  #plug_gw: !secret gw #gateway 
  #plug_nm: !secret nm #subnet
  #plug_dns_1: !secret dns_1
  #plug_dns_2: !secret dns_2
  ssid: !secret ssid
  wifi_pw: !secret wifi_pass
  fallback_pw: !secret fallback_pass
  api_pw: !secret api_pass
  ota_pw: !secret ota_pass

esphome:
  name: ${name}
  platform: ${platform}
  board: ${board}
  on_boot:
    priority: -10
    # hiermee zet je de blauwe stausled uit....(wel ook de switch definieren)
    then:
      - switch.turn_off: statusled

wifi:
  ssid: ${ssid}
  password: ${wifi_pw}
  fast_connect: True
# Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: ${name}_Hotspot
    password: ${fallback_pw}

# Enable Web server
web_server:
  port: 80
  
# Enable logging
logger:

# Enable Home Assistant API
api:
  password: ${api_pw}

ota:
  password: ${ota_pw}

captive_portal:



# configuration
status_led:
  pin:
    number: GPIO2
    inverted: true

switch:
  - platform: gpio
    pin: GPIO2
    name: wekker-statusled
    inverted: true
    id: statusled

# Exposed switches
  - platform: restart
    name: restart


# globals for testing
globals:
  - id: alarm_hour
    type: float
    restore_value: yes
    initial_value: "6"
  - id: alarm_minute
    type: float
    restore_value: yes
    initial_value: "00"
  - id: alarm_seconds
    type: float
    restore_value: yes
    initial_value: "21600" # 6:00 is 21600s na middernacht

# sensors   
sensor:
  - platform: rotary_encoder
    name: "Rotary Encoder"
    pin_a: D6
    pin_b: D7
    id: wekker_rotary
    on_clockwise:
      - logger.log: "op"
      - if:
          condition:
            binary_sensor.is_on: wekker_menu_mode
          then:
            - if:
                condition:
                  binary_sensor.is_on: set_alarmtime_mode
                then: 
                - lambda: |-
                    if (id(alarm_hour) < 23) {
                    id(alarm_hour) += 1;
                    id(alarm_seconds) += 3600;
                    } 
                    else {
                    id(alarm_hour) = 0;
                    id(alarm_seconds) = id(alarm_minute) * 60;
                    }
                else:
                - lambda: |-
                    if (id(alarm_minute) < 59) {
                    id(alarm_minute) += 1;
                    id(alarm_seconds) += 60;
                    } 
                    else {
                    id(alarm_minute) = 0;
                    id(alarm_seconds) = id(alarm_hour) * 3600;
                    }
      - sensor.template.publish:
          id: esp_alarm_minute
          state:  !lambda 'return id(alarm_minute);'
      - sensor.template.publish:
          id: esp_alarm_hour
          state: !lambda 'return id(alarm_hour);'
      - sensor.template.publish:
          id: esp_alarm_seconds
          state: !lambda 'return id(alarm_seconds);'
    on_anticlockwise:
      - logger.log: "neer"
      - if:
          condition:
            binary_sensor.is_on: wekker_menu_mode
          then:
            - if:
                condition:
                  binary_sensor.is_on: set_alarmtime_mode
                then: 
                - lambda: |-
                    if (id(alarm_hour) > 0) {
                    id(alarm_hour) -= 1;
                    id(alarm_seconds) -= 3600;
                    } 
                    else {
                    id(alarm_hour) = 23;
                    id(alarm_seconds) = (23 * 3600) + id(alarm_minute) * 60;
                    };
                else:
                - lambda: |-
                    if (id(alarm_minute) > 0) {
                    id(alarm_minute) -= 1;
                    id(alarm_seconds) -= 60;
                    } 
                    else {
                    id(alarm_minute) = 59;
                    id(alarm_seconds) = id(alarm_hour) * 3600 + (59 * 60);
                    };
      - sensor.template.publish:
          id: esp_alarm_minute
          state:  !lambda 'return id(alarm_minute);'
      - sensor.template.publish:
          id: esp_alarm_hour
          state:  !lambda 'return id(alarm_hour);'
      - sensor.template.publish:
          id: esp_alarm_seconds
          state:  !lambda 'return id(alarm_seconds);'
  - platform: template
    name: "ESP Alarm Hour"
    id: "esp_alarm_hour"
    lambda: |-
      return id(alarm_hour);
    accuracy_decimals: 0
  - platform: template
    name: "ESP Alarm Minute"
    id: "esp_alarm_minute"
    lambda: |-
      return id(alarm_minute);
    accuracy_decimals: 0 
  - platform: template
    name: "ESP Alarm Seconds"
    id: "esp_alarm_seconds"
    lambda: |-
      return id(alarm_seconds);
    accuracy_decimals: 0 

  # Extra sensor to keep an eye on the Wi-Fi signal
  - platform: wifi_signal
    name: ${name}_Wi-Fi_Signal
    update_interval: 60s

# Extra sensor to keep track of plug uptime
  - platform: uptime
    name: ${name}_Uptime
    id: uptime_s
    update_interval: 15s


# binary sensors    
binary_sensor:
  - platform: template
    name: "Selection Mode Active"
    id: wekker_menu_mode
    lambda: return {};
  - platform: template
    name: "SetAlarm Mode Active"
    id: set_alarmtime_mode
    lambda: return {};
  - platform: homeassistant
    entity_id: input_boolean.wakeup_enabled
    name: "Alarm Active"
    id: alarm_mode
  - platform: template
    name: "Button Short Click"
    id: wekker_button_click
    lambda: return {};
  - platform: template
    name: "Button Long Click"
    id: wekker_button_long_click
    lambda: return {};
  - platform: gpio
    pin:
      number: D5
      mode: INPUT_PULLUP
      inverted: true
    name: "Rotary Button"
    id: wekker_button

    on_multi_click:
    - timing:
      - ON for at most 500ms
      - OFF for at most 500ms
      - ON for at most 500ms
      - OFF for at least 200ms
      then:
        - logger.log: "Double Click"
        - switch.turn_off: statusled
        - if:
            condition:
              binary_sensor.is_off: wekker_menu_mode
            then:
              - lambda: id(wekker_menu_mode).publish_state(true);
            else:
              - lambda: id(wekker_menu_mode).publish_state(false);
    - timing:
      - ON for at most 1000ms
      - OFF for at least 500ms
      then:
        - logger.log: "Single short Click"
        - switch.turn_off: statusled
        - if:
            condition:
              binary_sensor.is_off: set_alarmtime_mode
            then:
              - lambda: id(set_alarmtime_mode).publish_state(true);
            else:
              - lambda: id(set_alarmtime_mode).publish_state(false);
        - lambda: id(wekker_button_click).publish_state(true);
        - delay: 2s
        - lambda: id(wekker_button_click).publish_state(false);
    - timing:
      - ON for at least 1000ms
      - OFF for at least 500ms
      then:
        - logger.log: "Single Long Click"
        - if:
            condition:
              binary_sensor.is_off: alarm_mode
            then:
              - lambda: id(alarm_mode).publish_state(true);
            else:
              - lambda: id(alarm_mode).publish_state(false);
        - lambda: id(wekker_button_long_click).publish_state(true);
        - delay: 2s
        - lambda: id(wekker_button_long_click).publish_state(false);
        - homeassistant.service:
            service: input_boolean.toggle
            data_template:
              entity_id: input_boolean.wakeup_enabled
        - switch.turn_off: statusled

# max7219 2x 4x8x7 matrix led display
spi:
  clk_pin: D2
  mosi_pin: D4

display:
  - platform: max7219
    cs_pin: D3
    num_chips: 1
    intensity: 0
    lambda: |-
      if (id(wekker_menu_mode).state) { // als je het alarm instelt

        if (id(alarm_mode).state) { // 
            it.print(7, "A");
        } else {
            it.printf(7, " "); 
        }

        if (id(alarm_hour) > 9) { // als het alarmuur 2 cijfers heeft gewoon printen
          it.printf(2, "%i", (int)id(alarm_hour)); // print de alarmuren
        } else {
          it.printf(2, "0%i", (int)id(alarm_hour)); // print de alarmuren met 0 ervoor
        }
        it.printf(3, ".");
        if (id(alarm_minute) > 9) { // als het alarmminute 2 cijfers heeft gewoon printen
          it.printf(4, "%i", (int)id(alarm_minute));
        } else {
          it.printf(4, "0%i", (int)id(alarm_minute));
        }
        
        } else {
        if (id(alarm_mode).state) { // als het alarm actief is print alarmtijd
          if (id(alarm_hour) > 9) { // als het alarmuur 2 cijfers heeft gewoon printen
            it.printf(4, "%i", (int)id(alarm_hour)); // print de alarmuren
          } else {
            it.printf(4, " %i", (int)id(alarm_hour)); // print de alarmuren met " " ervoor
          }

          it.printf(5, ".");
          
          if (id(alarm_minute) > 9) { // als het alarmminute 2 cijfers heeft gewoon printen
            it.printf(6, "%i", (int)id(alarm_minute));
          } else {
            it.printf(6, "0%i", (int)id(alarm_minute));
          }
        } else {} // geen alarmtijd als alarm niet actief is
        static int j = 0; // om de : te laten knipperen per seconde
        j++;
        if ((j % 2) == 0) { // bij elke even j
          it.strftime(0, "%H", id(sntp_time).now()); // print de huidige tijd met :
          it.print(1, ".");
          it.strftime(2, "%M", id(sntp_time).now());
        } else { // bij elke oneven j
          it.strftime(0, "%H", id(sntp_time).now()); // print de huidige tijd
          it.strftime(2, "%M", id(sntp_time).now());
          }
      }

time:
  - platform: sntp
    id: sntp_time
    timezone: Europe/Amsterdam
    
# Text sensors with general information
text_sensor:
  # Expose ESPHome version as sensor.
  - platform: version
    name: ${name}_esphome_version
  # Expose WiFi information as sensors.
  - platform: wifi_info
    ip_address:
      name: ${name}_wifi_ip
      icon: mdi:ip
    ssid:
      name: ${name}_wifi_ssid
      icon: mdi:wifi
    bssid:
      name: ${name}_wifi_bssid
      icon: mdi:wifi
  - platform: template
    name: ${name}_Uptime_Sensor
    lambda: |-
      uint32_t dur = id(uptime_s).state;
      int dys = 0;
      int hrs = 0;
      int mnts = 0;
      if (dur > 86399) {
        dys = trunc(dur / 86400);
        dur = dur - (dys * 86400);
      }
      if (dur > 3599) {
        hrs = trunc(dur / 3600);
        dur = dur - (hrs * 3600);
      }
      if (dur > 59) {
        mnts = trunc(dur / 60);
        dur = dur - (mnts * 60);
      }
      char buffer[17];
      sprintf(buffer, "%ud %02uh %02um %02us", dys, hrs, mnts, dur);
      return {buffer};
    icon: mdi:clock-start
    update_interval: 15s


2 Likes