From 16e60508adc9c075a86344d455f036d99fea501f Mon Sep 17 00:00:00 2001 From: gryf Date: Fri, 30 Sep 2022 10:02:47 +0200 Subject: [PATCH] initial import --- pywmcurrencies/__init__.py | 0 pywmcurrencies/pywmcurrencies.py | 273 +++++++++++++++++++++++++++++++ 2 files changed, 273 insertions(+) create mode 100644 pywmcurrencies/__init__.py create mode 100755 pywmcurrencies/pywmcurrencies.py diff --git a/pywmcurrencies/__init__.py b/pywmcurrencies/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pywmcurrencies/pywmcurrencies.py b/pywmcurrencies/pywmcurrencies.py new file mode 100755 index 0000000..e9f1f7e --- /dev/null +++ b/pywmcurrencies/pywmcurrencies.py @@ -0,0 +1,273 @@ +#!/usr/bin/env python +""" +Simple dockapp to show up temperature for selected labels +""" +import argparse +import datetime +import os +import re +import sys +import time + +import requests +import wmdocklib +from wmdocklib import helpers +from wmdocklib import pywmgeneral +import yaml + + +XDG_CONF_DIR = os.getenv('XDG_CONFIG_HOME', os.path.expanduser('~/.config')) +# expected bitmap contained font should be found in the same location as main +# program +BACKGROUND = '''\ +/* XPM */ +static char *mask_text[] = { +/* columns rows colors chars-per-pixel */ +"64 64 4 1 ", +" c None", +". c black", +"X c #202020", +"O c gray78", +/* pixels */ +" ", +" ", +" ............................................................ ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO ", +" OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO ", +" ", +" " +}; +''' +FONT = '''\ +/* XPM */ +static char *_x8_lcd_arrows[] = { +/* columns rows colors chars-per-pixel */ +"192 16 4 1 ", +" c #202020", +". c #004941", +"X c #188A86", +"o c #20B2AE", +/* pixels */ +" ... .X. o.o o.o .o. X...X oo. ..o ..o o.. ... ... ... ... ... ...X ooo ...X XoooX XoooX o...o XoooX XoooX XoooX XoooX XoooX ... ... ..oX ... Xo.. XoooX ", +". . . o . .o o. .X X. .XXXo o o o X. . X. . X . . X . o o . X . . . . . . . . o o o . o . o . o o o o . o . . o o o o o . . . . . X . . . . X . o o ", +". . . o . .X X. oXXXo o . . X. .XX . . X . .X . . X. .X X. . X . . . . . . . . X. o o . o . o . o o o o . o . . o o o o o . X . . X . .X . oXXXo . X. . o ", +" ... .X. ... o.o ooo .o. o.. ... o.. ..o XoooX XoooX ... XoooX ... .o. X...X ...X XoooX oooX XoooX ooooX XoooX ...X XoooX XoooX ... ... X... ... ...X ..oX ", +". . . o . . . oXXXo . o .X . o X o . . .X . . X. .X X. . X . . . . . . . .X . o o . o o . . o . o . o o o . o o o . o . . . . .X . oXXXo . X. . X . ", +". . . . . . .X X. oXXX. o o o X. . . . X . . X . o o . X . . X . . . . XX. o . o o . o o . . o . o . o o o . o o o . o . X . . X . . X . . . . X . . . ", +" ... .o. ... o.o .o. X...X oo.X ... ..o o.. ... ... .o. ... .oo X... ooo ...X XoooX XoooX ...X XoooX XoooX ...o XoooX XoooX ... .o. ..oX ... Xo.. .o. ", +" X X ", +" ooo ooo Xooo ooo Xooo XoooX XoooX oooX X...X .X. XoooX X...X X... oXo Xooo ooo Xooo ooo Xooo ooo XoXoX X...X X...X X...X X...X X...X XoooX .o. .o. .o. .o. ... ", +"o o o o o o o . o o o . o . o . o o . o . . o o o o . o o o o o o o o o o o o o o X . o . o o o o o o o o o o . o . X . .o o. .XXX. .X X. . . ", +"o XXo o o o o o . o o o . o . o . o o . o . . o o o o . o o o o o o o o o o o o o o . . o . o o o o o o Xo oX oX Xo . oX . X . . o . o X o o o . . ", +"X.o.X XoooX Xooo X... X...X XoooX Xooo X..oo XoooX .X. ...X Xooo X... X.X.X X...X X...X Xooo X...X Xooo ooo .X. X...X X...X X.X.X .ooo. .o.o. .o. .o. ... .o. ... ... ", +"o XXo o o o o o . o o o . o . o o o o . o . . o o o o . o o o o o o o o . o o o o o . o . o . o o o o o o o Xo oX . o . Xo . o X o . . . X . . . . . ", +"o o o o o o . o o o . o . o o o o . o . o o o o o . o o o o o o o o . o oo o o X o . o . o o Xo oX o o o o o . o . o . .XXX. . . . X . . . . . ", +" ooo X...X Xooo ooo Xooo XoooX X... ooo X...X .X. ooo X...X XoooX X. .X X...X ooo X... oooX X...X ooo .o. ooo XoX XoXoX X...X .X. XoooX .o. ... .o. ... ... ", +" " +}; +''' + + +class SensorDockApp(wmdocklib.DockApp): + """ + Discover and display values for defined in config temperatures or other + readings using information found on /sys file system. + """ + background_color = '#202020' + + def __init__(self, args=None): + super().__init__(args) + self.fonts = [wmdocklib.BitmapFonts(FONT, (6, 8))] + self.background = BACKGROUND + self.conf = {} + self.critical = 0 + self.warning = 0 + self._data = {} + self._read_config() + self._current_graph = '' + + def run(self): + self.prepare_pixmaps() + self.open_xwindow() + try: + self.main_loop() + except KeyboardInterrupt: + pass + + def main_loop(self): + + count = 0 + while True: + position = 1 + if count == 0: + for currency in self.conf.get('currencies', [])[:7]: + value = self.get_rate_string(currency) + self._put_string(currency, value, position) + position += self.fonts[0].height + 1 + + count += 1 + if count >= 10: + count = 0 + self.redraw() + time.sleep(0.1) + + def get_rate_string(self, currency): + self._get_rates() + + previous, current = self._data[currency] + + if len(str(int(current))) > 5: + return 'ERROR' + + arrow = ']' # ↑ + if current - previous < 0: + arrow = '[' # ↓ + + string = f'{current:.2f}{arrow}' + + amount = 0 + while len(string) < 5: + zeros = '0' * amount + string = f'{current:.2f}{zeros}{arrow}' + amount += 1 + + return string + + def _get_rates(self): + now = datetime.datetime.now() + end_date = now.strftime("%Y-%m-%d") + # this is arbitrary number, since we have space for around 60, and + # there is no rating at holidays and weekends, so that makes around 20 + # rates per month. + start_date = (now - datetime.timedelta(days=10)).strftime("%Y-%m-%d") + + if (self._data.get('_last_update') and + (now - self._data['_last_update']).seconds < 7500): + # don't hammer npb service to often + return + + for currency in self.conf.get('currencies'): + url = (f'http://api.nbp.pl/api/exchangerates/rates/a/{currency}/' + f'{start_date}/{end_date}/') + try: + response = requests.get(url) + except requests.ConnectionError: + return + + if response.status_code != 200: + print(f'error requesting data for currency "{currency} on ' + f'time range between {start_date} and {end_date}') + return + + self._data['_last_update'] = now + result = response.json() + previous, current = [x['mid'] + for x in result.get('rates', [])][-2:] + self._data[currency] = (previous, current) + + def _switch_graph(self): + currencies = self.conf.get('currencies') + idx = currencies.index(self._current_graph) + try: + self._current_graph = currencies[idx + 1] + except IndexError: + self._current_graph = currencies[0] + + def _read_config(self): + conf = os.path.join(XDG_CONF_DIR, 'pywmcurrencies.yaml') + if self.args.config: + conf = self.args.config + + try: + with open(conf) as fobj: + self.conf = yaml.safe_load(fobj) + except OSError: + # TODO: add some logging? + pass + + def _put_string(self, currency, value, position): + name = f'{currency[:3]:3}'.upper() + self.fonts[0].add_string(name, 1, position) + self.fonts[0].add_string(value, 28, position) + + def _draw_graph_label(self): + name = self._current_graph.upper() + name = name[:4] + # ugly as hell 1 pixel border for the upper and left side of the label + helpers.copy_xpm_area(1, 65, + len(name) * self.fonts[0].width + 1, 1, + 4, 51) + helpers.copy_xpm_area(1, 65, + 1, self.fonts[0].height + 1, + 4, 51) + self.fonts[0].add_string(name, 2, 49) + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('-c', '--config', help='Alternate config file') + args = parser.parse_args() + + dockapp = SensorDockApp(args) + dockapp.run() + + +if __name__ == '__main__': + main()