diff --git a/README.rst b/README.rst index b6dbc0e..90343e8 100644 --- a/README.rst +++ b/README.rst @@ -224,6 +224,10 @@ application (and the "blank" white screen is a torch application): :alt: Countdown timer application running in the wasp-os simulator :width: 179 +.. image:: res/WeatherApp.png + :alt: Weather application running in the wasp-os simulator + :width: 179 + .. image:: res/WordClkApp.png :alt: Shows a time as words in the wasp-os simulator :width: 179 diff --git a/docs/apps.rst b/docs/apps.rst index 01e1e16..350c5d5 100644 --- a/docs/apps.rst +++ b/docs/apps.rst @@ -53,6 +53,8 @@ Applications .. automodule:: apps.timer +.. automodule:: apps.weather + Games ----- diff --git a/res/WeatherApp.png b/res/WeatherApp.png new file mode 100644 index 0000000..a143775 Binary files /dev/null and b/res/WeatherApp.png differ diff --git a/res/weather_icon.png b/res/weather_icon.png new file mode 100644 index 0000000..44b86ec Binary files /dev/null and b/res/weather_icon.png differ diff --git a/wasp/apps/software.py b/wasp/apps/software.py index bc345b5..dcc412e 100644 --- a/wasp/apps/software.py +++ b/wasp/apps/software.py @@ -49,6 +49,7 @@ class SoftwareApp(): db.append(('flashlight', factory('Torch'))) db.append(('testapp', factory('Test'))) db.append(('timer', factory('Timer'))) + db.append(('weather', factory('Weather'))) db.append(('word_clock', factory('Word Clock'))) # Get the initial state for the checkboxes diff --git a/wasp/apps/weather.py b/wasp/apps/weather.py new file mode 100644 index 0000000..2e44da4 --- /dev/null +++ b/wasp/apps/weather.py @@ -0,0 +1,164 @@ +# SPDX-License-Identifier: LGPL-3.0-or-later +# Copyright (C) 2020 Daniel Thompson +# Copyright (C) 2020 Carlos Gil + +"""Weather for GadgetBridge and wasp-os companion +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + .. figure:: res/WeatherApp.png + :width: 179 + + Screenshot of the Weather application + +""" + +import wasp + +import icons +import time +import fonts.sans36 + +# 2-bit RLE, generated from res/weather_icon.png, 309 bytes +icon = ( + b'\x02' + b'`@' + b'\x1e\xa4<\xa4<\xa4;\xa5?Y\xec2\xf0/\xf2-' + b'\xf4,\xc3@;n\xc3,\xc3n\xc3,\xc3n\xc3,' + b'\xc3n\xc3,\xc3n\xc3,\xc3n\xc3,\xc3n\xc3,' + b'\xc3n\xc3,\xc3n\xc3,\xc3O\x80\xd3\x87X\xc3,' + b'\xc3M\x8bV\xc3,\xc3K\x8fT\xc3,\xc3J\x91S' + b'\xc3,\xc3I\x93R\xc3,\xc3H\x95Q\xc3,\xc3H' + b'\x95Q\xc3,\xc3G\x97P\xc3,\xc3G\x97P\xc3+' + b'\xc4F\x99O\xc3*\xc5F\x99O\xc3*\xc5F\x99O' + b'\xc3*\xc5F\x99O\xc3*\xc5F\x99O\xc3*\xc5F' + b'\x99\xc4K\xc3*\xc5F\x8e\xc5\x84\xc1\x81\xc5J\xc3*' + b'\xc5G\x8c\xc8\x81\xcaH\xc3+\xc4G\x83\xc5\x83\xd6F' + b'\xc3,\xc3H\x81\xe0E\xc3,\xc3G\xe2E\xc3,\xc3' + b'G\xe3D\xc3,\xc3F\xe4D\xc3,\xc3F\xe4D\xc3' + b',\xc3F\xe4D\xc3,\xc3F\xe4D\xc3,\xc3F\xe3' + b'E\xc3,\xc3G\xe2E\xc3,\xc3G\xe1F\xc3,\xc3' + b'H\xc9A\xccC\xc5H\xc3,\xc3J\xc5E\xc9Q\xc3' + b',\xc3V\xc5S\xc3,\xc3n\xc3,\xc3n\xc3,\xc3' + b'n\xc3,\xc3n\xc3,\xc3n\xc3,\xc3n\xc3,\xf4' + b'-\xf2/\xf02\xec?X\xc0\xdb\xe6;\xe4<\xe4<' + b'\xe4\x1e' +) + +class WeatherApp(object): + """ Weather application.""" + NAME = 'Weather' + ICON = icon + + def __init__(self): + self._temp = '' + self._hum = '' + self._txt = '' + self._wind = '' + self._loc = '' + self._temp_changed = True + self._hum_changed = True + self._txt_changed = True + self._wind_changed = True + self._loc_changed = True + + def foreground(self): + """Activate the application.""" + temp = wasp.system.weatherinfo.get('temp') + hum = wasp.system.weatherinfo.get('hum') + txt = wasp.system.weatherinfo.get('txt') + wind = wasp.system.weatherinfo.get('wind') + loc = wasp.system.weatherinfo.get('loc') + if temp: + self._temp = temp + if hum: + self._hum = hum + if txt: + self._txt = txt + if wind: + self._wind = wind + if loc: + self._loc = loc + wasp.watch.drawable.fill() + self.draw() + wasp.system.request_tick(1000) + + def background(self): + """De-activate the application (without losing state).""" + self._temp_changed = True + self._hum_changed = True + self._txt_changed = True + self._wind_changed = True + self._loc_changed = True + + def tick(self, ticks): + wasp.system.keep_awake() + temp_now = wasp.system.weatherinfo.get('temp') + hum_now = wasp.system.weatherinfo.get('hum') + txt_now = wasp.system.weatherinfo.get('txt') + wind_now = wasp.system.weatherinfo.get('wind') + loc_now = wasp.system.weatherinfo.get('loc') + if temp_now: + if temp_now != self._temp: + self._temp = temp_now + self._temp_changed = True + else: + self._temp_changed = False + if hum_now: + if hum_now != self._hum: + self._hum = hum_now + self._hum_changed = True + else: + self._hum_changed = False + if txt_now: + if txt_now != self._txt: + self._txt = txt_now + self._txt_changed = True + else: + self._txt_changed = False + if wind_now: + if wind_now != self._wind: + self._wind = wind_now + self._wind_changed = True + else: + self._wind_changed = False + if loc_now: + if loc_now != self._loc: + self._loc = loc_now + self._loc_changed = True + else: + self._loc_changed = False + wasp.system.weatherinfo = {} + self._update() + + def draw(self): + """Redraw the display from scratch.""" + self._draw() + + def _draw(self): + """Redraw the updated zones.""" + if self._temp_changed: + self._draw_label(self._temp, 54, 36) + if self._hum_changed: + self._draw_label("Humidity: "+self._hum, 160) + if self._txt_changed: + self._draw_label(self._txt, 12) + if self._wind_changed: + self._draw_label("Wind: "+self._wind, 120) + if self._loc_changed: + self._draw_label(self._loc, 200) + + def _draw_label(self, label, pos, size = 24): + """Redraw label info""" + if label: + draw = wasp.watch.drawable + draw.reset() + if size == 36: + draw.set_font(fonts.sans36) + + draw.string(label, 0, pos, 240) + + def _update(self): + self._draw() + + def update(self): + pass diff --git a/wasp/boards/manifest_240x240.py b/wasp/boards/manifest_240x240.py index ccd4f64..2f59436 100644 --- a/wasp/boards/manifest_240x240.py +++ b/wasp/boards/manifest_240x240.py @@ -24,6 +24,7 @@ manifest = ( 'apps/snake.py', 'apps/testapp.py', 'apps/timer.py', + 'apps/weather.py', 'apps/word_clock.py', 'fonts/__init__.py', 'fonts/clock.py', diff --git a/wasp/boards/simulator/main.py b/wasp/boards/simulator/main.py index 78a1168..618fae5 100644 --- a/wasp/boards/simulator/main.py +++ b/wasp/boards/simulator/main.py @@ -13,6 +13,14 @@ wasp.system.set_music_info({ 'artist': 'Dreams of Bamboo', }) +wasp.system.set_weather_info({ + 'temp': '22', + 'hum': '100%', + 'txt': 'Cloudy', + 'wind': '25km/h', + 'loc': 'Toronto' +}) + # Increase the display blanking time to avoid spamming the console # with backlight activations. diff --git a/wasp/gadgetbridge.py b/wasp/gadgetbridge.py index 18285ab..dc5479a 100644 --- a/wasp/gadgetbridge.py +++ b/wasp/gadgetbridge.py @@ -56,6 +56,8 @@ def GB(cmd): wasp.system.toggle_music(cmd) elif task == 'musicinfo': wasp.system.set_music_info(cmd) + elif task == 'weather': + wasp.system.set_weather_info(cmd) else: pass #_info('Command "{}" is not implemented'.format(cmd)) diff --git a/wasp/wasp.py b/wasp/wasp.py index abcb974..5b1a8b8 100644 --- a/wasp/wasp.py +++ b/wasp/wasp.py @@ -117,6 +117,7 @@ class Manager(): self.notifications = {} self.musicstate = {} self.musicinfo = {} + self.weatherinfo = {} self._theme = ( b'\x7b\xef' # ble @@ -320,6 +321,9 @@ class Manager(): def set_music_info(self, info): self.musicinfo = info + def set_weather_info(self, info): + self.weatherinfo = info + def set_alarm(self, time, action): """Queue an alarm.