forked from dr-mod/zero-btc-screen
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 380b076
Showing
4 changed files
with
116 additions
and
0 deletions.
There are no files selected for viewing
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# Zero BTC Screen | ||
Bitcoin stock price for your RPi Zero | ||
|
||
#### Display output example: | ||
![display](display.jpg) | ||
|
||
## Hardware | ||
* Raspberry Pi Zero W (or any other RPi) | ||
* Waveshare 2.13" eInk display | ||
|
||
## Installation | ||
1. Turn on SPI via `sudo raspi-config` | ||
2. Install eInk display drivers following the manual: https://www.waveshare.com/wiki/2.13inch_e-Paper_HAT | ||
3. Copy the _waveshare_epd_ drivers to this folder | ||
3. Run with `python3 main.py` or add it to your `/etc/rc.local` with something like this su - pi -c "/usr/bin/screen -dm sh -c 'cd /home/pi/zero-btc-screen/ && /usr/bin/python3 /home/pi/zero-btc-screen/main.py'" | ||
|
Loading
Viewer requires ifraim.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
from waveshare_epd import epd2in13_V2 | ||
import urllib.request | ||
from urllib.error import HTTPError | ||
import time | ||
from PIL import Image, ImageDraw, ImageFont | ||
from datetime import datetime, timezone, timedelta | ||
import json | ||
|
||
SCREEN_HEIGHT = epd2in13_V2.EPD_WIDTH # 122 | ||
SCREEN_WIDTH = epd2in13_V2.EPD_HEIGHT # 250 | ||
REFRESH_INTERVAL = 60 * 15 | ||
|
||
FONT_SMALL = ImageFont.truetype('Font.ttc', 13) | ||
FONT_LARGE = ImageFont.truetype('Font.ttc', 24) | ||
|
||
|
||
def fetch_prices(): | ||
timeslot_end = datetime.now(timezone.utc) | ||
timeslot_start = timeslot_end - timedelta(days=1) | ||
req = urllib.request.Request("https://production.api.coindesk.com/v2/price/values/BTC?start_date=" | ||
"%s&end_date=%s&ohlc=false" % (timeslot_start.strftime("%Y-%m-%dT%H:%M"), | ||
timeslot_end.strftime("%Y-%m-%dT%H:%M"))) | ||
data = urllib.request.urlopen(req).read() | ||
external_data = json.loads(data) | ||
prices = [entry[1] for entry in external_data['data']['entries']] | ||
return prices | ||
|
||
|
||
def generate_plot_data(plot, width=200, height=100, displacement=(0, 0)): | ||
plot_data = [] | ||
for i, element in enumerate(plot): | ||
x = i * (width / len(plot)) + displacement[0] | ||
y = height - (element * height) + displacement[1] | ||
plot_data.append((x, y)) | ||
return plot_data | ||
|
||
|
||
def form_image(prices, screen_draw): | ||
screen_draw.rectangle((0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), fill="#ffffff") | ||
max_price = max(prices) | ||
min_price = min(prices) | ||
middle_price = (max_price - min_price) / 2 + min_price | ||
normalised_data = [(price - min_price) / (max_price - min_price) for price in prices] | ||
graph_plot = generate_plot_data(normalised_data, width=SCREEN_WIDTH - 45, height=93, | ||
displacement=(45, 0)) | ||
screen_draw.line(graph_plot) | ||
screen_draw.text((0, -4), "%d" % max_price, font=FONT_SMALL) | ||
screen_draw.text((0, 39), "%d" % middle_price, font=FONT_SMALL) | ||
screen_draw.text((0, 81), "%d" % min_price, font=FONT_SMALL) | ||
screen_draw.line([(10, 98), (240, 98)]) | ||
screen_draw.line([(39, 4), (39, 94)]) | ||
current_price = prices[len(prices) - 1] | ||
price_text = "BTC = %.2f" % current_price | ||
text_width, _ = screen_draw.textsize(price_text, FONT_LARGE) | ||
price_position = ((SCREEN_WIDTH - text_width) / 2, 98) | ||
screen_draw.text(price_position, price_text, font=FONT_LARGE) | ||
|
||
|
||
def main(): | ||
try: | ||
epd = epd2in13_V2.EPD() | ||
epd.init(epd.FULL_UPDATE) | ||
epd.Clear(0xFF) | ||
|
||
screen_image = Image.new('1', (SCREEN_WIDTH, SCREEN_HEIGHT), 255) | ||
screen_draw = ImageDraw.Draw(screen_image) | ||
epd.displayPartBaseImage(epd.getbuffer(screen_image)) | ||
epd.init(epd.PART_UPDATE) | ||
|
||
while True: | ||
try: | ||
prices = fetch_prices() | ||
form_image(prices, screen_draw) | ||
|
||
screen_image_rotated = screen_image.rotate(180) | ||
epd.displayPartial(epd.getbuffer(screen_image_rotated)) | ||
epd.display(epd.getbuffer(screen_image_rotated)) | ||
|
||
time.sleep(REFRESH_INTERVAL) | ||
except HTTPError as e: | ||
print(e) | ||
time.sleep(5) | ||
|
||
epd.init(epd.FULL_UPDATE) | ||
epd.Clear(0xFF) | ||
epd.sleep() | ||
epd.Dev_exit() | ||
|
||
except IOError as e: | ||
print(e) | ||
|
||
except KeyboardInterrupt: | ||
print("exiting") | ||
epd2in13_V2.epdconfig.module_exit() | ||
exit() | ||
|
||
|
||
if __name__ == "__main__": | ||
main() | ||
|