#!/usr/bin/env python3
"""
lcd_weatherclock.py - A program that displays a clock on an LCD screen
and shows weather information for 10 seconds when a button is pressed.
"""
from LCD import LCD
import datetime
import time
import requests
import os
from dotenv import load_dotenv
from gpiozero import Button
import threading
# Load environment variables from .env file
load_dotenv()
# Initialize LCD
lcd = LCD(2, 0x27, True)
lcd.clear()
# Initialize button with debounce
button = Button(21, pull_up=True, bounce_time=0.2) # 200ms debounce time
# Global variables
display_mode = "clock" # Can be "clock" or "weather"
weather_timer = None
def get_etobicoke_weather():
"""
Get current weather for Etobicoke, Ontario, Canada using OpenWeatherMap API
"""
try:
# OpenWeatherMap API endpoint for current weather
url = "https://api.openweathermap.org/data/2.5/weather"
# Get APP ID for weather api
OPENWEATHERMAPAPIKEY = os.getenv("openweathermapapikey")
# Parameters for Etobicoke, Ontario, Canada
params = {
"q": "Etobicoke,Ontario,CA",
"units": "metric", # For Celsius
"appid": OPENWEATHERMAPAPIKEY # API key
}
# Make the API request
response = requests.get(url, params=params)
# Check if the request was successful
if response.status_code == 200:
# Parse the JSON response
weather_data = response.json()
# Extract relevant information
temperature = weather_data["main"]["temp"]
condition = weather_data["weather"][0]["main"]
humidity = weather_data["main"]["humidity"]
return {
"temperature": temperature,
"condition": condition,
"humidity": humidity
}
else:
return {"error": f"API Error: {response.status_code}"}
except Exception as e:
return {"error": f"Error: {str(e)}"}
def display_weather(lcd):
"""
Display weather data on the LCD
"""
global display_mode
# Set display mode to weather
display_mode = "weather"
# Show loading message
lcd.clear()
lcd.message("Weather...")
# Get weather data
weather_data = get_etobicoke_weather()
lcd.clear()
if "error" in weather_data:
lcd.message("Weather Error")
lcd.message(weather_data["error"][:16], 2) # Truncate to fit LCD width
else:
# Format and display weather information
temp_str = f"Temp: {weather_data['temperature']:.1f}C"
cond_str = f"{weather_data['condition']} {weather_data['humidity']}%"
lcd.message(temp_str)
lcd.message(cond_str, 2)
# Set a timer to switch back to clock after 10 seconds
global weather_timer
if weather_timer:
weather_timer.cancel()
weather_timer = threading.Timer(10.0, switch_to_clock)
weather_timer.start()
def switch_to_clock():
"""
Switch display back to clock mode
"""
global display_mode
display_mode = "clock"
# The main loop will update the display on the next iteration
def display_clock(lcd, force_update=False):
"""
Display clock on the LCD
"""
now = datetime.datetime.now()
currenttime = now.strftime("%H:%M:%S")
currentdate = now.strftime("%d-%m-%Y")
# Only update if time/date changed or force update is requested
if force_update or currenttime != display_clock.lasttime or currentdate != display_clock.lastdate:
lcd.clear()
lcd.message('%02d:%02d:%02d' % (now.hour, now.minute, now.second), 1)
lcd.message('%02d-%02d-%04d' % (now.day, now.month, now.year), 2)
display_clock.lasttime = currenttime
display_clock.lastdate = currentdate
# Initialize static variables for display_clock function
display_clock.lasttime = ''
display_clock.lastdate = ''
def button_pressed():
"""Function called when button is pressed"""
global display_mode
if display_mode == "clock":
display_weather(lcd)
# Assign callback function to button press event
button.when_pressed = button_pressed
# Display welcome message
lcd.message("Weather Clock")
lcd.message("Starting...", 2)
time.sleep(2)
lcd.clear()
# Main loop
try:
while True:
if display_mode == "clock":
display_clock(lcd)
time.sleep(0.1)
except KeyboardInterrupt:
# Clean up on exit
if weather_timer:
weather_timer.cancel()
lcd.clear()
print("\nExiting program")