URI: 
       tCommit code. - btcticker - eInk Bitcoin price ticker
  HTML git clone https://git.parazyd.org/btcticker
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit 82552df78bc40de87e59608e561194521fa85d59
  HTML Author: parazyd <parazyd@dyne.org>
       Date:   Fri, 19 Feb 2021 16:12:08 +0100
       
       Commit code.
       
       Diffstat:
         A LICENSE                             |      22 ++++++++++++++++++++++
         A README.md                           |       4 ++++
         A fonts/PixelSplitter-Bold.ttf        |       0 
         A fonts/googlefonts/LICENSE.txt       |     202 +++++++++++++++++++++++++++++++
         A fonts/googlefonts/Roboto-Light.ttf  |       0 
         A fonts/googlefonts/Roboto-Medium.ttf |       0 
         A images/ATH.bmp                      |       0 
         A images/currency/bitcoin.bmp         |       0 
         A ticker.py                           |     169 +++++++++++++++++++++++++++++++
       
       9 files changed, 397 insertions(+), 0 deletions(-)
       ---
   DIR diff --git a/LICENSE b/LICENSE
       t@@ -0,0 +1,22 @@
       +MIT License
       +
       +Copyright (c) 2021 parazyd <parazyd@dyne.org>
       +Copyright (c) 2020 llvll
       +
       +Permission is hereby granted, free of charge, to any person obtaining a copy
       +of this software and associated documentation files (the "Software"), to deal
       +in the Software without restriction, including without limitation the rights
       +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       +copies of the Software, and to permit persons to whom the Software is
       +furnished to do so, subject to the following conditions:
       +
       +The above copyright notice and this permission notice shall be included in all
       +copies or substantial portions of the Software.
       +
       +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
       +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
       +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
       +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
       +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
       +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
       +SOFTWARE.
   DIR diff --git a/README.md b/README.md
       t@@ -0,0 +1,4 @@
       +eInk Bitcoin price ticker
       +=========================
       +
       +Adapted from https://github.com/llvllch/btcticker
   DIR diff --git a/fonts/PixelSplitter-Bold.ttf b/fonts/PixelSplitter-Bold.ttf
       Binary files differ.
   DIR diff --git a/fonts/googlefonts/LICENSE.txt b/fonts/googlefonts/LICENSE.txt
       t@@ -0,0 +1,202 @@
       +
       +                                 Apache License
       +                           Version 2.0, January 2004
       +                        http://www.apache.org/licenses/
       +
       +   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
       +
       +   1. Definitions.
       +
       +      "License" shall mean the terms and conditions for use, reproduction,
       +      and distribution as defined by Sections 1 through 9 of this document.
       +
       +      "Licensor" shall mean the copyright owner or entity authorized by
       +      the copyright owner that is granting the License.
       +
       +      "Legal Entity" shall mean the union of the acting entity and all
       +      other entities that control, are controlled by, or are under common
       +      control with that entity. For the purposes of this definition,
       +      "control" means (i) the power, direct or indirect, to cause the
       +      direction or management of such entity, whether by contract or
       +      otherwise, or (ii) ownership of fifty percent (50%) or more of the
       +      outstanding shares, or (iii) beneficial ownership of such entity.
       +
       +      "You" (or "Your") shall mean an individual or Legal Entity
       +      exercising permissions granted by this License.
       +
       +      "Source" form shall mean the preferred form for making modifications,
       +      including but not limited to software source code, documentation
       +      source, and configuration files.
       +
       +      "Object" form shall mean any form resulting from mechanical
       +      transformation or translation of a Source form, including but
       +      not limited to compiled object code, generated documentation,
       +      and conversions to other media types.
       +
       +      "Work" shall mean the work of authorship, whether in Source or
       +      Object form, made available under the License, as indicated by a
       +      copyright notice that is included in or attached to the work
       +      (an example is provided in the Appendix below).
       +
       +      "Derivative Works" shall mean any work, whether in Source or Object
       +      form, that is based on (or derived from) the Work and for which the
       +      editorial revisions, annotations, elaborations, or other modifications
       +      represent, as a whole, an original work of authorship. For the purposes
       +      of this License, Derivative Works shall not include works that remain
       +      separable from, or merely link (or bind by name) to the interfaces of,
       +      the Work and Derivative Works thereof.
       +
       +      "Contribution" shall mean any work of authorship, including
       +      the original version of the Work and any modifications or additions
       +      to that Work or Derivative Works thereof, that is intentionally
       +      submitted to Licensor for inclusion in the Work by the copyright owner
       +      or by an individual or Legal Entity authorized to submit on behalf of
       +      the copyright owner. For the purposes of this definition, "submitted"
       +      means any form of electronic, verbal, or written communication sent
       +      to the Licensor or its representatives, including but not limited to
       +      communication on electronic mailing lists, source code control systems,
       +      and issue tracking systems that are managed by, or on behalf of, the
       +      Licensor for the purpose of discussing and improving the Work, but
       +      excluding communication that is conspicuously marked or otherwise
       +      designated in writing by the copyright owner as "Not a Contribution."
       +
       +      "Contributor" shall mean Licensor and any individual or Legal Entity
       +      on behalf of whom a Contribution has been received by Licensor and
       +      subsequently incorporated within the Work.
       +
       +   2. Grant of Copyright License. Subject to the terms and conditions of
       +      this License, each Contributor hereby grants to You a perpetual,
       +      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
       +      copyright license to reproduce, prepare Derivative Works of,
       +      publicly display, publicly perform, sublicense, and distribute the
       +      Work and such Derivative Works in Source or Object form.
       +
       +   3. Grant of Patent License. Subject to the terms and conditions of
       +      this License, each Contributor hereby grants to You a perpetual,
       +      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
       +      (except as stated in this section) patent license to make, have made,
       +      use, offer to sell, sell, import, and otherwise transfer the Work,
       +      where such license applies only to those patent claims licensable
       +      by such Contributor that are necessarily infringed by their
       +      Contribution(s) alone or by combination of their Contribution(s)
       +      with the Work to which such Contribution(s) was submitted. If You
       +      institute patent litigation against any entity (including a
       +      cross-claim or counterclaim in a lawsuit) alleging that the Work
       +      or a Contribution incorporated within the Work constitutes direct
       +      or contributory patent infringement, then any patent licenses
       +      granted to You under this License for that Work shall terminate
       +      as of the date such litigation is filed.
       +
       +   4. Redistribution. You may reproduce and distribute copies of the
       +      Work or Derivative Works thereof in any medium, with or without
       +      modifications, and in Source or Object form, provided that You
       +      meet the following conditions:
       +
       +      (a) You must give any other recipients of the Work or
       +          Derivative Works a copy of this License; and
       +
       +      (b) You must cause any modified files to carry prominent notices
       +          stating that You changed the files; and
       +
       +      (c) You must retain, in the Source form of any Derivative Works
       +          that You distribute, all copyright, patent, trademark, and
       +          attribution notices from the Source form of the Work,
       +          excluding those notices that do not pertain to any part of
       +          the Derivative Works; and
       +
       +      (d) If the Work includes a "NOTICE" text file as part of its
       +          distribution, then any Derivative Works that You distribute must
       +          include a readable copy of the attribution notices contained
       +          within such NOTICE file, excluding those notices that do not
       +          pertain to any part of the Derivative Works, in at least one
       +          of the following places: within a NOTICE text file distributed
       +          as part of the Derivative Works; within the Source form or
       +          documentation, if provided along with the Derivative Works; or,
       +          within a display generated by the Derivative Works, if and
       +          wherever such third-party notices normally appear. The contents
       +          of the NOTICE file are for informational purposes only and
       +          do not modify the License. You may add Your own attribution
       +          notices within Derivative Works that You distribute, alongside
       +          or as an addendum to the NOTICE text from the Work, provided
       +          that such additional attribution notices cannot be construed
       +          as modifying the License.
       +
       +      You may add Your own copyright statement to Your modifications and
       +      may provide additional or different license terms and conditions
       +      for use, reproduction, or distribution of Your modifications, or
       +      for any such Derivative Works as a whole, provided Your use,
       +      reproduction, and distribution of the Work otherwise complies with
       +      the conditions stated in this License.
       +
       +   5. Submission of Contributions. Unless You explicitly state otherwise,
       +      any Contribution intentionally submitted for inclusion in the Work
       +      by You to the Licensor shall be under the terms and conditions of
       +      this License, without any additional terms or conditions.
       +      Notwithstanding the above, nothing herein shall supersede or modify
       +      the terms of any separate license agreement you may have executed
       +      with Licensor regarding such Contributions.
       +
       +   6. Trademarks. This License does not grant permission to use the trade
       +      names, trademarks, service marks, or product names of the Licensor,
       +      except as required for reasonable and customary use in describing the
       +      origin of the Work and reproducing the content of the NOTICE file.
       +
       +   7. Disclaimer of Warranty. Unless required by applicable law or
       +      agreed to in writing, Licensor provides the Work (and each
       +      Contributor provides its Contributions) on an "AS IS" BASIS,
       +      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
       +      implied, including, without limitation, any warranties or conditions
       +      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
       +      PARTICULAR PURPOSE. You are solely responsible for determining the
       +      appropriateness of using or redistributing the Work and assume any
       +      risks associated with Your exercise of permissions under this License.
       +
       +   8. Limitation of Liability. In no event and under no legal theory,
       +      whether in tort (including negligence), contract, or otherwise,
       +      unless required by applicable law (such as deliberate and grossly
       +      negligent acts) or agreed to in writing, shall any Contributor be
       +      liable to You for damages, including any direct, indirect, special,
       +      incidental, or consequential damages of any character arising as a
       +      result of this License or out of the use or inability to use the
       +      Work (including but not limited to damages for loss of goodwill,
       +      work stoppage, computer failure or malfunction, or any and all
       +      other commercial damages or losses), even if such Contributor
       +      has been advised of the possibility of such damages.
       +
       +   9. Accepting Warranty or Additional Liability. While redistributing
       +      the Work or Derivative Works thereof, You may choose to offer,
       +      and charge a fee for, acceptance of support, warranty, indemnity,
       +      or other liability obligations and/or rights consistent with this
       +      License. However, in accepting such obligations, You may act only
       +      on Your own behalf and on Your sole responsibility, not on behalf
       +      of any other Contributor, and only if You agree to indemnify,
       +      defend, and hold each Contributor harmless for any liability
       +      incurred by, or claims asserted against, such Contributor by reason
       +      of your accepting any such warranty or additional liability.
       +
       +   END OF TERMS AND CONDITIONS
       +
       +   APPENDIX: How to apply the Apache License to your work.
       +
       +      To apply the Apache License to your work, attach the following
       +      boilerplate notice, with the fields enclosed by brackets "[]"
       +      replaced with your own identifying information. (Don't include
       +      the brackets!)  The text should be enclosed in the appropriate
       +      comment syntax for the file format. We also recommend that a
       +      file or class name and description of purpose be included on the
       +      same "printed page" as the copyright notice for easier
       +      identification within third-party archives.
       +
       +   Copyright [yyyy] [name of copyright owner]
       +
       +   Licensed under the Apache License, Version 2.0 (the "License");
       +   you may not use this file except in compliance with the License.
       +   You may obtain a copy of the License at
       +
       +       http://www.apache.org/licenses/LICENSE-2.0
       +
       +   Unless required by applicable law or agreed to in writing, software
       +   distributed under the License is distributed on an "AS IS" BASIS,
       +   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       +   See the License for the specific language governing permissions and
       +   limitations under the License.
   DIR diff --git a/fonts/googlefonts/Roboto-Light.ttf b/fonts/googlefonts/Roboto-Light.ttf
       Binary files differ.
   DIR diff --git a/fonts/googlefonts/Roboto-Medium.ttf b/fonts/googlefonts/Roboto-Medium.ttf
       Binary files differ.
   DIR diff --git a/images/ATH.bmp b/images/ATH.bmp
       Binary files differ.
   DIR diff --git a/images/currency/bitcoin.bmp b/images/currency/bitcoin.bmp
       Binary files differ.
   DIR diff --git a/ticker.py b/ticker.py
       t@@ -0,0 +1,169 @@
       +#!/usr/bin/env python3
       +# Copyright (c) 2021 parazyd
       +# Copyright (c) 2020 llvll
       +#
       +# Permission is hereby granted, free of charge, to any person obtaining a copy
       +# of this software and associated documentation files (the "Software"), to deal
       +# in the Software without restriction, including without limitation the rights
       +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       +# copies of the Software, and to permit persons to whom the Software is
       +# furnished to do so, subject to the following conditions:
       +#
       +# The above copyright notice and this permission notice shall be included in
       +# all copies or substantial portions of the Software.
       +#
       +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
       +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
       +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
       +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
       +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
       +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
       +# SOFTWARE.
       +"""
       +Program to create a bitcoin ticker bitmap and show it on a waveshare 2in13_V2
       +eink screen (https://www.waveshare.com/wiki/2.13inch_e-Paper_HAT)
       +"""
       +
       +import sys
       +from os.path import join, dirname, realpath
       +from time import time, strftime, sleep
       +import matplotlib as mpl
       +import matplotlib.pyplot as plt
       +import numpy as np
       +from PIL import Image, ImageFont, ImageDraw
       +import requests
       +from waveshare_epd import epd2in13_V2
       +mpl.use('Agg')
       +
       +picdir = join(dirname(realpath(__file__)), 'images')
       +fontdir = join(dirname(realpath(__file__)), 'fonts')
       +font = ImageFont.truetype(join(fontdir, 'googlefonts/Roboto-Medium.ttf'), 40)
       +font_date = ImageFont.truetype(join(fontdir, 'PixelSplitter-Bold.ttf'), 11)
       +
       +API = 'https://api.coingecko.com/api/v3/coins'
       +
       +
       +def get_data(other):
       +    """ Grab data from API """
       +    days_ago = 7
       +    endtime = int(time())
       +    starttime = endtime - 60*60*24*days_ago
       +
       +    geckourl = '%s/markets?vs_currency=%s&ids=%s' % (API, 'usd', 'bitcoin')
       +    liveprice = requests.get(geckourl).json()[0]
       +    pricenow = float(liveprice['current_price'])
       +    alltimehigh = float(liveprice['ath'])
       +    other['volume'] = float(liveprice['total_volume'])
       +
       +    url_hist = '%s/%s/market_chart/range?vs_currency=%s&from=%s&to=%s' % (
       +                     API, 'bitcoin', 'usd', str(starttime), str(endtime))
       +
       +    timeseriesarray = requests.get(url_hist).json()['prices']
       +    timeseriesstack = []
       +    length = len(timeseriesarray)
       +    i = 0
       +    while i < length:
       +        timeseriesstack.append(float(timeseriesarray[i][1]))
       +        i += 1
       +
       +    timeseriesstack.append(pricenow)
       +    if pricenow > alltimehigh:
       +        other['ATH'] = True
       +    else:
       +        other['ATH'] = False
       +    return timeseriesstack
       +
       +
       +def make_spark(pricestack):
       +    """ Make a historical plot """
       +    _x = pricestack - np.mean(pricestack)
       +    fig, _ax = plt.subplots(1, 1, figsize=(10, 3))
       +    plt.plot(_x, color='k', linewidth=6)
       +    plt.plot(len(_x)-1, _x[-1], color='r', marker='o')
       +
       +    for _, i in _ax.spines.items():
       +        i.set_visible(False)
       +    _ax.set_xticks = ([])
       +    _ax.set_yticks = ([])
       +    _ax.axhline(c='k', linewidth=4, linestyle=(0, (5, 2, 1, 2)))
       +
       +    plt.savefig(join(picdir, 'spark.png'), dpi=17)
       +    imgspk = Image.open(join(picdir, 'spark.png'))
       +    file_out = join(picdir, 'spark.bmp')
       +    imgspk.save(file_out)
       +    plt.clf()
       +    _ax.cla()
       +    plt.close(fig)
       +
       +
       +def update_display(pricestack, other, epd):
       +    """ Create an image from the data and send it to the display """
       +    days_ago = 7
       +    pricenow = pricestack[-1]
       +    currencythumbnail = 'currency/bitcoin.bmp'
       +    tokenfilename = join(picdir, currencythumbnail)
       +    sparkbitmap = Image.open(join(picdir, 'spark.bmp'))
       +    athbitmap = Image.open(join(picdir, 'ATH.bmp'))
       +    tokenimage = Image.open(tokenfilename)
       +
       +    pricechange = str('%+d' % round(
       +        (pricestack[-1]-pricestack[0]) / pricestack[-1]*100, 2))+'%'
       +    if pricenow > 1000:
       +        pricenowstring = format(int(pricenow), ',')
       +    else:
       +        pricenowstring = str(float('%.5g' % pricenow))
       +
       +    image = Image.new('L', (250, 122), 255)
       +    draw = ImageDraw.Draw(image)
       +    if other['ATH'] is True:
       +        image.paste(athbitmap, (15, 30))
       +    else:
       +        image.paste(tokenimage, (0, 15))
       +
       +    image.paste(sparkbitmap, (80, 15))
       +    draw.text((130, 66), str(days_ago) + 'day : ' + pricechange,
       +              font=font_date, fill=0)
       +    draw.text((96, 73), '$'+pricenowstring, font=font, fill=0)
       +
       +    draw.text((95, 5), str(strftime('%H:%M %a %d %b %Y')), font=font_date,
       +              fill=0)
       +
       +    # image.save('pic.bmp')
       +    epd.display(epd.getbuffer(image))
       +
       +
       +def main():
       +    """ main routine """
       +    def fullupdate(epd):
       +        other = {}
       +        pricestack = get_data(other)
       +        make_spark(pricestack)
       +        update_display(pricestack, other, epd)
       +        lastgrab = time()
       +        return lastgrab
       +
       +    try:
       +        data_pulled = False
       +        lastcoinfetch = time()
       +
       +        epd = epd2in13_V2.EPD()
       +        epd.init(epd.FULL_UPDATE)
       +        epd.Clear(0xFF)
       +        # epd = None
       +
       +        while True:
       +            if (time() - lastcoinfetch > float(120)) or data_pulled is False:
       +                lastcoinfetch = fullupdate(epd)
       +                data_pulled = True
       +            sleep(5)
       +    except KeyboardInterrupt:
       +        epd.sleep()
       +        epd.Dev_exit()
       +        epd2in13_V2.epdconfig.module_exit()
       +        return 1
       +
       +    return 1
       +
       +
       +if __name__ == '__main__':
       +    sys.exit(main())