The Analog Weather Display

Hello friends,

Here is a weather-display I made with an ESP32 and a stepper motor. (28BYJ-48). It features a rotating disc with icons that rotate to display the weather forecast for the day.

weather_display

It uses a reed switch and a magnet for homing, ESPHome does all the heavy lifting. The code I have used is a mix of helpful code found on these forums. Sorry I have no idea where I got what, but all credit goes to the original authors. I really wanted to make it in wood, so I made a rendering of what that could look like, but I haven’t got the tools do make it, so 3D-print it is. Here’s the rendering anyways:

ESPHome:

esphome:
  name: weather_display
  platform: ESP32
  board: esp-wrover-kit
  on_boot:
    priority: -100
    then:
      - if:
          condition:
#           If global variable "stepper_position" is 0 AND endstop switch is also 0 (off), return 1, or else return 0
            lambda: "if ((id(stepper_position) == 0) && (id(endstop).state == 0)) { return 1; } else { return 0; }"
          then:
#             Set the global variable "homing_state" to 1 (Meaning it's calibrating)
            - globals.set:
                id: homing_state
                value: '1'
#             Set the current step number in the global variable "stepper_steps"
            - stepper.report_position:
                id: my_stepper
                position: !lambda "return id(stepper_steps)-4000;"
#               Move the stepper to zero (This has to do with the previous command, so it doesnt move)
            - stepper.set_target:
                id: my_stepper
                target: 0
#             Wait until the stepper is no longer moving
            - wait_until:
                - lambda: "if (id(my_stepper).current_position == id(my_stepper).target_position) { return 1; } else { return 0; }"
            - globals.set:
                id: homing_state
                value: '0'
      - if:
          condition:
            wifi.connected:
          then:
            - logger.log: WiFi is connected!
                    
wifi:
  ssid: "SSID HERE"
  password: "PWD HERE"
  ap:
    ssid: "Weather Display"
    password: "12345678"

captive_portal:

web_server:
  port: 80

# Enable logging
logger:

# Enable Home Assistant API
api:
  services:
    - service: control_stepper
      variables:
        target: int
      then:
        - stepper.set_target:
            id: my_stepper
            target: !lambda 'return target;'

ota:

    
stepper:
  - platform: uln2003
    id: my_stepper
    pin_a: 16
    pin_b: 17
    pin_c: 21
    pin_d: 22
    max_speed: 250 steps/s
    sleep_when_done: true
    acceleration: inf
    deceleration: inf

globals:
  - id: stepper_steps
    type: int
    initial_value: '0'
    restore_value: true
  - id: stepper_prevpos
    type: float
    initial_value: '0'
  - id: stepper_position
    type: float
    initial_value: '0'
  - id: stepper_state
    type: int
    initial_value: '0'
  - id: homing_state
    type: int
    initial_value: '0'

binary_sensor:
  - platform: gpio
    pin:
      number: 26
      mode: INPUT_PULLUP
    name: "Endstop"
    id: endstop
    filters:
        - invert:
    on_press:
      then: 
        - if: # If homing state is on
            condition:
              - lambda: 'return id(homing_state) != 0;'
            then: # Enter Homing
            - logger.log: Starting homing!

            - globals.set:
                id: stepper_prevpos
                value: !lambda "return id(my_stepper).current_position;"
            - stepper.report_position:
                id: my_stepper
                position: 0
            - stepper.set_target:
                id: my_stepper
                target: 0
 #           - globals.set:
#                id: homing_state
#                value: '0'
            
switch:
  - platform: template
    name: "Lightning"
    turn_on_action:
      - stepper.set_target:
                  id: my_stepper
                  target: 1367

  - platform: template
    name: "Partly Cloudy"
    turn_on_action:
      - stepper.set_target:
                  id: my_stepper
                  target: 1886
                  
  - platform: template
    name: "Rain"
    turn_on_action:
      - stepper.set_target:
                  id: my_stepper
                  target: 2308
                  
  - platform: template
    name: "Sunny"
    turn_on_action:
      - stepper.set_target:
                  id: my_stepper
                  target: 652
                  
  - platform: template
    name: "Cloudy"
    turn_on_action:
      - stepper.set_target:
                  id: my_stepper
                  target: 1009
                  
  - platform: template
    name: "Home"
    turn_on_action:
      - globals.set:
          id: homing_state
          value: '1'
      - if:
          condition:
#           If global variable "stepper_position" is 0 AND endstop switch is also 0 (off), return 1, or else return 0
            lambda: "if ((id(stepper_position) == 0) && (id(endstop).state == 0)) { return 1; } else { return 0; }"
          then:
#             Set the global variable "homing_state" to 1 (Meaning it's calibrating)
            - globals.set:
                id: homing_state
                value: '1'
#             Set the current step number in the global variable "stepper_steps"
            - stepper.report_position:
                id: my_stepper
                position: !lambda "return id(stepper_steps)-4000;"
#               Move the stepper to zero (This has to do with the previous command, so it doesnt move)
            - stepper.set_target:
                id: my_stepper
                target: 0
#             Wait until the stepper is no longer moving
            - wait_until:
                - lambda: "if (id(my_stepper).current_position == id(my_stepper).target_position) { return 1; } else { return 0; }"
            - globals.set:
                id: homing_state
                value: '0'

Automation:

- alias: Display clear night
  trigger:
    platform: state
    entity_id: weather.home
    to: 'clear-night'
  action:
    - service: homeassistant.turn_on
      entity_id: switch.home
    - delay:
        seconds: 6
    - service: homeassistant.turn_on
      entity_id: switch.sunny

- alias: Display cloudy
  trigger:
    platform: state
    entity_id: weather.home
    to: 'cloudy'
  action:
    - service: homeassistant.turn_on
      entity_id: switch.home
    - delay:
        seconds: 6
    - service: homeassistant.turn_on
      entity_id: switch.cloudy

- alias: Display fog
  trigger:
    platform: state
    entity_id: weather.home
    to: 'fog'
  action:
    - service: homeassistant.turn_on
      entity_id: switch.home
    - delay:
        seconds: 6
    - service: homeassistant.turn_on
      entity_id: switch.cloudy

- alias: Display hail
  trigger:
    platform: state
    entity_id: weather.home
    to: 'hail'
  action:
    - service: homeassistant.turn_on
      entity_id: switch.home    
    - delay:
        seconds: 6
    - service: homeassistant.turn_on
      entity_id: switch.rain

- alias: Display lightning
  trigger:
    platform: state
    entity_id: weather.home
    to: 'lightning'
  action:
    - service: homeassistant.turn_on
      entity_id: switch.home    
    - delay:
        seconds: 6
    - service: homeassistant.turn_on
      entity_id: switch.lightning

- alias: Display lightning-rainy
  trigger:
    platform: state
    entity_id: weather.home
    to: 'lightning-rainy'
  action:
    - service: homeassistant.turn_on
      entity_id: switch.home
    - delay:
        seconds: 6
    - service: homeassistant.turn_on
      entity_id: switch.lightning

- alias: Display partlycloudy
  trigger:
    platform: state
    entity_id: weather.home
    to: 'partlycloudy'
  action:
    - service: homeassistant.turn_on
      entity_id: switch.home
    - delay:
        seconds: 6
    - service: homeassistant.turn_on
      entity_id: switch.partly_cloudy

- alias: Display pouring
  trigger:
    platform: state
    entity_id: weather.home
    to: 'pouring'
  action:
    - service: homeassistant.turn_on
      entity_id: switch.home    
    - delay:
        seconds: 6
    - service: homeassistant.turn_on
      entity_id: switch.rain

- alias: Display rainy
  trigger:
    platform: state
    entity_id: weather.home
    to: 'rainy'
  action:
    - service: homeassistant.turn_on
      entity_id: switch.home    
    - delay:
        seconds: 6
    - service: homeassistant.turn_on
      entity_id: switch.rain

- alias: Display snowy
  trigger:
    platform: state
    entity_id: weather.home
    to: 'snowy'
  action:
    - service: homeassistant.turn_on
      entity_id: switch.home 
    - delay:
        seconds: 6   
    - service: homeassistant.turn_on
      entity_id: switch.rain

- alias: Display snowy-rainy
  trigger:
    platform: state
    entity_id: weather.home
    to: 'snowy-rainy'
  action:
    - service: homeassistant.turn_on
      entity_id: switch.home    
    - delay:
        seconds: 6
    - service: homeassistant.turn_on
      entity_id: switch.rain

- alias: Display sunny
  trigger:
    platform: state
    entity_id: weather.home
    to: 'sunny'
  action:
    - service: homeassistant.turn_on
      entity_id: switch.home    
    - delay:
        seconds: 6
    - service: homeassistant.turn_on
      entity_id: switch.sunny

- alias: Display windy
  trigger:
    platform: state
    entity_id: weather.home
    to: 'windy'
  action:
    - service: homeassistant.turn_on
      entity_id: switch.home    
    - delay:
        seconds: 6
    - service: homeassistant.turn_on
      entity_id: switch.cloudy

- alias: Display windy-variant
  trigger:
    platform: state
    entity_id: weather.home
    to: 'windy-variant'
  action:
    - service: homeassistant.turn_on
      entity_id: switch.home   
    - delay:
        seconds: 6 
    - service: homeassistant.turn_on
      entity_id: switch.cloudy

- alias: Display exceptional
  trigger:
    platform: state
    entity_id: weather.home
    to: 'exceptional'
  action:
    - service: homeassistant.turn_on
      entity_id: switch.home    
    - delay:
        seconds: 6
    - service: homeassistant.turn_on
      entity_id: switch.rainy
11 Likes