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.
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