0

I'm a bit rusty with python, so hopefully I'm just doing something silly. I'm trying to create a simple weather widget using appJar and the OpenWeatherMap, and the UI isn't updated as expected when the network response returns. I read the appJar documentation and I know I need to kick off the network request on another thread, and then enqueue the UI change when the response comes back, but it doesn't seem to be working. It's a very simple application so far, here's the entirety of the code:

app.py

from appJar import gui
import datetime, pyowm, WeatherUtils
from WeatherInfo import WeatherInfo

LES_LAT = 40.714080
LES_LON = -73.985890

app = gui()
app.setBg("#363636")
app.setSize("Fullscreen")

# Date and time
def addDateTimeLabel(labelName: str, text: str) -> None:
    app.addLabel(labelName, text)
    app.setLabelFg(labelName, "White")
    app.setLabelFont(labelName, size=32)

now = datetime.datetime.now()
date = now.strftime("%A %B %e, %Y")
time = now.strftime("%l:%M %p")

addDateTimeLabel("date", date)
addDateTimeLabel("time", time)

# Weather UI
addDateTimeLabel('current_weather', 'Loading...')
addDateTimeLabel('forecast', 'Loading...')

app.go()

# Weather Data Fetch
def setCurrentWeatherData(weather_data: WeatherInfo) -> None:
    weather_string = 'Current: ' + weather_data.status + " " + str(weather_data.temp) + ", High: " + str(weather_data.max_temp) + ", Low: " + str(weather_data.min_temp)
    app.queueFunction(app.setLabel, 'current_weather', weather_string)

app.thread(WeatherUtils.getCurrentTemperature, LES_LAT, LES_LON, setCurrentWeatherData)

WeatherUtils.py

from typing import Callable, List
from WeatherInfo import WeatherInfo
import pyowm, datetime
from pyowm.weatherapi25.observation import Observation

OPEN_WEATHER_MAP_API_KEY = "XXXXXXXX"
owm = pyowm.OWM(OPEN_WEATHER_MAP_API_KEY)

def createWeatherInfoFromResponse(observation: Observation) -> WeatherInfo:
    weather_data = observation.get_weather()
    temperature_data = weather_data.get_temperature('fahrenheit')
    if temperature_data is None:
        return

    weather = WeatherInfo(temperature_data.get('temp'), temperature_data.get('temp_min'), temperature_data.get('temp_max'), weather_data.get_detailed_status().title())

    weather.snow = weather_data.get_snow()
    weather.icon_url = weather_data.get_weather_icon_url()
    weather.sunrise_time = weather_data.get_sunrise_time()
    weather.sunset_time = weather_data.get_sunset_time()
    weather.humidity = weather_data.get_humidity()
    wind_data = weather_data.get_wind()
    if wind_data is not None:
        weather.wind_direction = wind_data.get('deg')
        weather.wind_speed = wind_data.get('speed')

    weather.reference_time = weather_data.get_reference_time()
    weather.location = observation.get_location().get_name()
    return weather

def getCurrentTemperature(lat: float, lon: float, callback: Callable[[WeatherInfo], None]) -> None:
    weather_observation = owm.weather_at_coords(lat, lon)
    weather = createWeatherInfoFromResponse(weather_observation)
    if weather is not None:
        callback(weather)

WeatherInfo.py

class WeatherInfo:
    def __init__(self, temp: float, min_temp: float, max_temp: float, status: str):
        self.temp = temp
        self.min_temp = min_temp
        self.max_temp = max_temp
        self.status = status
        self.snow = None
        self.humidity = None
        self.icon_url = None
        self.sunrise_time = None
        self.sunset_time = None
        self.wind_direction = None
        self.wind_speed = None
        self.reference_time = None
        self.location = None

    def get_sunrise_time(self) -> str:
        return self.sunrise_time.strftime('%l:%M %p')

    def get_sunset_time(self) -> str:
        return self.sunset_time.strftime('%l:%M %p')

    def get_reference_time(self) -> str:
        return self.reference_time.strftime('%l:%M %p')

Any advice is much appreciated. Thank you!

Mason
  • 6,893
  • 15
  • 71
  • 115

1 Answers1

1

Figured out the answer here. For anyone else struggling with this, the label update call needs to be enqueued before the label itself is added to the UI. Here's code for app.py that seems to work as expected:

from appJar import gui
import datetime, pyowm, WeatherUtils
from WeatherInfo import WeatherInfo

LES_LAT = 40.714080
LES_LON = -73.985890

app = gui()
app.setBg("#363636")
app.setSize("Fullscreen")

# Date and time
def addDateTimeLabel(labelName: str, text: str) -> None:
    app.addLabel(labelName, text)
    app.setLabelFg(labelName, "White")
    app.setLabelFont(labelName, size=32)

now = datetime.datetime.now()
date = now.strftime("%A %B %e, %Y")
time = now.strftime("%l:%M %p")

addDateTimeLabel("date", date)
addDateTimeLabel("time", time)

# Weather Data Fetch
def setCurrentWeatherData(weather_data: WeatherInfo) -> None:
    weather_string = 'Current: ' + weather_data.status + " " + str(weather_data.temp) + ", High: " + str(weather_data.max_temp) + ", Low: " + str(weather_data.min_temp)
    app.queueFunction(app.setLabel, 'current_weather', weather_string)

app.thread(WeatherUtils.getCurrentTemperature, LES_LAT, LES_LON, setCurrentWeatherData)

# Weather UI
addDateTimeLabel('current_weather', 'Loading...')
addDateTimeLabel('forecast', 'Loading...')

app.go()

If anyone has any insight into why this is the case, it'd be much appreciated, but figured I'd answer the question in case others were running into the same issue.

Mason
  • 6,893
  • 15
  • 71
  • 115