Add option to show USD/BTC price ticker

This commit is contained in:
Taylor Helsper 2021-12-03 11:05:50 -06:00
parent ff44c5c780
commit d93a095a08
11 changed files with 221 additions and 55 deletions

View File

@ -9,6 +9,7 @@ from device_info import *
from thread_functions import *
from systemctl_info import *
from application_info import *
from price_info import *
from messages import *
if isPython3():
from io import StringIO, BytesIO
@ -63,6 +64,17 @@ def api_get_lightning_info():
return jsonify(data)
@mynode_api.route("/api/get_price_info")
def api_get_price_info():
check_logged_in()
data = {}
data["price"] = get_latest_price()
data["delta"] = get_price_diff_24hrs()
data["direction"] = get_price_up_down_flat_24hrs()
return jsonify(data)
@mynode_api.route("/api/get_service_status")
def api_get_service_status():
check_logged_in()
@ -193,7 +205,7 @@ def api_toggle_setting():
setting = request.args.get("setting")
if setting == "pinned_lightning_details":
toggle_pinned_lightning_details()
toggle_ui_setting("pinned_lightning_details")
data["status"] = "success"
else:
data["status"] = "unknown_setting"

View File

@ -31,6 +31,7 @@ except:
local_ip = "unknown"
cached_data = {}
warning_data = {}
ui_settings = None
#==================================
# Manage Device
@ -458,7 +459,22 @@ def get_drive_info(drive):
#==================================
# UI Functions
#==================================
def init_ui_setting_defaults(ui_settings):
if "darkmode" not in ui_settings:
ui_settings["darkmode"] = False
if "price_ticker" not in ui_settings:
ui_settings["price_ticker"] = False
if "pinned_lightning_details" not in ui_settings:
ui_settings["pinned_lightning_details"] = False
if "background" not in ui_settings:
ui_settings["background"] = "none"
return ui_settings
def read_ui_settings():
global ui_settings
if ui_settings != None:
return ui_settings
ui_hdd_file = '/mnt/hdd/mynode/settings/ui.json'
ui_mynode_file = '/home/bitcoin/.mynode/ui.json'
@ -470,19 +486,20 @@ def read_ui_settings():
elif os.path.isfile(ui_mynode_file):
with open(ui_mynode_file, 'r') as fp:
ui_settings = json.load(fp)
# if ui.json is not found anywhere, use default settings
else:
ui_settings = {'darkmode': False}
# Set reseller
ui_settings["reseller"] = is_device_from_reseller()
ui_settings = init_ui_setting_defaults(ui_settings)
return ui_settings
def write_ui_settings(ui_settings):
def write_ui_settings(ui_settings_new):
global ui_settings
ui_settings = ui_settings_new
ui_hdd_file = '/mnt/hdd/mynode/settings/ui.json'
ui_mynode_file = '/home/bitcoin/.mynode/ui.json'
try:
with open(ui_hdd_file, 'w') as fp:
json.dump(ui_settings, fp)
@ -492,42 +509,18 @@ def write_ui_settings(ui_settings):
with open(ui_mynode_file, 'w') as fp:
json.dump(ui_settings, fp)
def is_darkmode_enabled():
def get_ui_setting(name):
ui_settings = read_ui_settings()
return ui_settings['darkmode']
return ui_settings[name]
def disable_darkmode():
def set_ui_setting(name, value):
ui_settings = read_ui_settings()
ui_settings['darkmode'] = False
ui_settings[name] = value
write_ui_settings(ui_settings)
def enable_darkmode():
ui_settings = read_ui_settings()
ui_settings['darkmode'] = True
write_ui_settings(ui_settings)
def toggle_ui_setting(name):
set_ui_setting(name, not get_ui_setting(name))
def toggle_darkmode():
if is_darkmode_enabled():
disable_darkmode()
else:
enable_darkmode()
def toggle_pinned_lightning_details():
ui_settings = read_ui_settings()
if "pinned_lightning_details" not in ui_settings or ui_settings["pinned_lightning_details"] == False:
ui_settings["pinned_lightning_details"] = True
else:
ui_settings["pinned_lightning_details"] = False
write_ui_settings(ui_settings)
def set_background(background):
ui_settings = read_ui_settings()
ui_settings['background'] = background
write_ui_settings(ui_settings)
def get_background():
ui_settings = read_ui_settings()
return ui_settings['background']
# def get_background_choices():
# choices = []

View File

@ -31,6 +31,7 @@ from device_info import *
from device_warnings import *
from systemctl_info import *
from application_info import *
from price_info import *
import pam
import re
import json
@ -752,6 +753,9 @@ def start_threads():
lnd_thread = BackgroundThread(update_lnd_info_thread, 60)
lnd_thread.start()
threads.append(lnd_thread)
price_thread = BackgroundThread(update_price_info_thread, 30) # 5 minutes
price_thread.start()
threads.append(price_thread)
drive_thread = BackgroundThread(update_device_info, 60)
drive_thread.start()
threads.append(drive_thread)

View File

@ -0,0 +1,60 @@
from utilities import *
from device_info import *
import subprocess
import json
import time
import os
price_data = []
def get_latest_price():
global price_data
if len(price_data) > 0:
return price_data[len(price_data) - 1]["price"]
return "N/A"
def get_price_diff_24hrs():
global price_data
latest = get_latest_price()
if len(price_data) > 0:
old = price_data[0]["price"]
if latest != "N/A" and old != "N/A":
return latest - old
return 0.0
def get_price_up_down_flat_24hrs():
diff = get_price_diff_24hrs()
if diff > 10:
return "up"
elif diff < -10:
return "down"
return "flat"
def update_price_info():
global price_data
if get_ui_setting("price_ticker"):
price = "N/A"
try:
price_json_string = subprocess.check_output("torify curl https://api.coindesk.com/v1/bpi/currentprice.json", shell=True)
data = json.loads(price_json_string)
price = data["bpi"]["USD"]["rate_float"]
except:
pass
# Add latest price
now = int(time.time())
d = {}
d["time"] = now
d["price"] = price
price_data.append(d)
# only keep 24 hours of updates
while len(price_data) > 0:
d = price_data[0]
if d["time"] < now - 24*60*60:
price_data.pop(0)
else:
break

View File

@ -10,7 +10,7 @@ from threading import Timer
from thread_functions import *
from user_management import check_logged_in
from lightning_info import *
from thread_functions import *
from price_info import *
from utilities import *
from application_info import *
import pam
@ -983,15 +983,24 @@ def ping_page():
@mynode_settings.route("/settings/toggle-darkmode")
def toggle_darkmode_page():
check_logged_in()
toggle_darkmode()
toggle_ui_setting("darkmode")
flash("Darkmode Setting Updated", category="message")
return redirect("/settings")
@mynode_settings.route("/settings/toggle-darkmode-home")
def toggle_darkmode_page_home():
check_logged_in()
toggle_darkmode()
toggle_ui_setting("darkmode")
return redirect("/")
@mynode_settings.route("/settings/toggle-price-ticker")
def toggle_price_ticker_page():
check_logged_in()
toggle_ui_setting("price_ticker")
update_price_info()
flash("Price Ticker Setting Updated", category="message")
return redirect("/settings")
@mynode_settings.route("/settings/set-background", methods=['POST'])
def set_background_page():
check_logged_in()
@ -1001,8 +1010,9 @@ def set_background_page():
return redirect("/settings")
bg = request.form.get('background')
set_background(bg)
set_ui_setting("background", bg)
flash("Background Updated", category="message")
return redirect("/settings")
@mynode_settings.route("/settings/toggle-netdata")
@ -1013,6 +1023,8 @@ def toggle_netdata_page():
disable_service("netdata")
else:
enable_service("netdata")
flash("Netdata Setting Updated", category="message")
return redirect("/settings")
@mynode_settings.route("/settings/toggle-check-external-drive")

View File

@ -249,6 +249,16 @@ td, th {
background: #f0f0f0;
}
/* width of four tiles (full width) */
.app_tile_price_ticker {
display: inline-block;
position: relative;
border: none;
border-radius: 10px;
width: 810px;
height: 20px;
padding: 6px 10px 6px 10px;
background: #f0f0f0;
}
.app_tile_bitcoin_recent_blocks {
display: inline-block;
position: relative;
@ -695,10 +705,10 @@ a:link.ui-button, a:visited.ui-button, .ui-button {
.main_page_warning_block {
color: #333333;
border: 3px solid orange;
border: 2px solid orange;
background-color: rgb(255, 250, 238);
width: 800px;
border-radius: 25px;
width: 810px;
border-radius: 10px;
text-align: justify;
display: block;
font-size: 12px;
@ -709,10 +719,10 @@ a:link.ui-button, a:visited.ui-button, .ui-button {
.main_page_error_block {
color: #333333;
border: 3px solid red;
border: 2px solid red;
background-color: rgb(255, 238, 238);
width: 800px;
border-radius: 25px;
width: 810px;
border-radius: 10px;
text-align: justify;
display: block;
font-size: 12px;
@ -725,12 +735,12 @@ a:link.ui-button, a:visited.ui-button, .ui-button {
display: none;
position: fixed;
color: #333333;
border: 3px solid orange;
border: 2px solid orange;
background-color: rgb(255, 250, 238);
width: 800px;
width: 810px;
left: 50%;
margin-left: -400px;
border-radius: 25px;
border-radius: 10px;
text-align: center;
font-size: 14px;
padding: 20px;

View File

@ -40,6 +40,7 @@ a:active {
.device_status_info,
.bitcoin_block,
.pair_wallet_text,
.app_tile_price_ticker,
.app_tile_lightning_details,
.lightning_channel_container,
.settings_block_subheader,
@ -54,6 +55,7 @@ table,
.app_tile,
.app_tile_short,
.app_tile_wide,
.app_tile_price_ticker,
.app_tile_bitcoin_recent_blocks,
.app_tile_lightning_details,
.info_tile {
@ -62,6 +64,7 @@ table,
.app_tile,
.app_tile_wide,
.app_tile_price_ticker,
.app_tile_bitcoin_recent_blocks,
.app_tile_lightning_details,
.app_tile_short {
@ -140,7 +143,7 @@ th td {
.bottom_center_alert_popup,
.halving_message_main_page {
color: #ddd;
border: 3px solid orange;
border: 2px solid orange;
background-color: #3a4750;
}

View File

@ -99,9 +99,16 @@
</div>
</div>
<!-- Show Price Info -->
<div class="app_tile_row" id="price_ticker" style="display: none;">
<div class="app_tile_price_ticker" >
<span id="price_ticker_text"></span>
</div>
</div>
<!-- Show Bitcoin Blocks -->
<div class="app_tile_row">
<div class="app_tile_bitcoin_recent_blocks" id="bitcoin_blocks" style="display: none;">
<div class="app_tile_row" id="bitcoin_blocks" style="display: none;">
<div class="app_tile_bitcoin_recent_blocks" >
<div class="bitcoin_block_set"></div>
<div class="bitcoin_block">
<div class="bitcoin_block_orange_square">
@ -164,8 +171,8 @@
</div>
<!-- Show Lightning Details -->
<div class="app_tile_row">
<div class="app_tile_lightning_details" id="lightning_details" style="display: none;">
<div class="app_tile_row" id="lightning_details" style="display: none;">
<div class="app_tile_lightning_details">
<!-- Top Wallet Section -->
<p style="font-size: 16px; font-weight: bold;">Wallet</p>

View File

@ -18,6 +18,7 @@
var is_installing_docker_images = {% if is_installing_docker_images %}true{% else %}false{% endif %};
var lnd_last_btc_tx = "";
var lnd_last_ln_tx = "";
var price_data = {};
// Toggle enable/disable functions
function get_custom_enable_message(short_name) {
@ -96,6 +97,36 @@
}
}
var price_display_rotate_count = 0;
function update_price_display() {
{% if ui_settings['price_ticker'] %}
if ("price" in price_data && "delta" in price_data && "direction" in price_data ) {
$("#price_ticker").show();
$("#price_ticker_text").slideUp('fast', function() {
display_id = price_display_rotate_count % 3;
if (display_id == 0) {
p = price_data["price"].toLocaleString('en-US', {style: 'currency', currency: 'USD'});
$("#price_ticker_text").html(p + " USD/BTC");
} else if (display_id == 1) {
sats = parseInt(100000000 / price_data["price"]);
$("#price_ticker_text").html(sats + " SATS/USD");
} else if (display_id == 2) {
p = Math.abs(price_data["delta"]).toLocaleString('en-US', {style: 'currency', currency: 'USD'});
if (price_data["direction"] == "flat") {
$("#price_ticker_text").html("Price is flat");
} else if (price_data["direction"] == "up") {
$("#price_ticker_text").html("Price is up "+p);
} else if (price_data["direction"] == "down") {
$("#price_ticker_text").html("Price is down "+p);
}
}
$("#price_ticker_text").slideDown();
price_display_rotate_count = price_display_rotate_count + 1;
});
}
{% endif %}
}
function update_sso_token(short_name, data) {
if ("sso_token" in data && data["sso_token"] != null && data["sso_token"] != "") {
application_data[short_name]["sso_token"] = data["sso_token"]
@ -350,6 +381,17 @@
{% endif %}
{% endfor %}
// Update price info
$.getJSON("/api/get_price_info", function( data ) {
console.log("Price Data: " + JSON.stringify(data))
if ("price" in data && data["price"] != null) {
price_data = data;
if (price_display_rotate_count == 0) {
update_price_display();
}
}
});
// Update device info
$.getJSON("/api/get_device_info", function( data ) {
//console.log("Device Data: " + JSON.stringify(data))
@ -572,6 +614,9 @@
const update_interval = setInterval(update_page, 15000);
update_page();
// Rotate Price Ticker every 10 seconds
const rotate_ticker_interval = setInterval(update_price_display, 10000);
// If pinned lightning, auto open lightning details
{% if lnd_wallet_exists and lnd_ready and ui_settings['pinned_lightning_details'] %}
setTimeout(toggleLightningDetails, 1500);

View File

@ -631,6 +631,17 @@
<div class="divider"></div>
<div class="settings_block_subheader">Price Ticker</div>
Display recent Bitcoin price on the main page.
<br/>
{% if ui_settings['price_ticker'] %}
<a href="/settings/toggle-price-ticker" class="ui-button ui-widget ui-corner-all settings_button">Disable</a>
{% else %}
<a href="/settings/toggle-price-ticker" class="ui-button ui-widget ui-corner-all settings_button">Enable</a>
{% endif %}
<div class="divider"></div>
<div class="settings_block_subheader">Background</div>
For fun, you can set a background image.
<br/><br/>

View File

@ -9,6 +9,7 @@ from device_info import *
from enable_disable_functions import *
from systemctl_info import *
from electrum_info import update_electrs_info
from price_info import update_price_info
from requests import get
import random
@ -22,7 +23,6 @@ swap_usage = "..."
device_temp = "..."
public_ip = "not_detected"
# Getters
def get_has_updated_btc_info():
global has_updated_btc_info
@ -160,6 +160,15 @@ def update_lnd_info_thread():
print("CAUGHT update_lnd_info_thread EXCEPTION: " + str(e))
# Updates price info every 5 minutes
def update_price_info_thread():
try:
# Get Price Info
update_price_info()
except Exception as e:
print("CAUGHT update_price_info_thread EXCEPTION: " + str(e))
# Check every 3 hours
def find_public_ip():
global public_ip