Added single page stats back to Gerty
This commit is contained in:
parent
b1c9e9a87e
commit
a0a7ae9be1
3 changed files with 887 additions and 630 deletions
|
|
@ -239,3 +239,42 @@ def get_time_remaining(seconds, granularity=2):
|
||||||
name = name.rstrip("s")
|
name = name.rstrip("s")
|
||||||
result.append("{} {}".format(round(value), name))
|
result.append("{} {}".format(round(value), name))
|
||||||
return ", ".join(result[:granularity])
|
return ", ".join(result[:granularity])
|
||||||
|
|
||||||
|
|
||||||
|
async def get_mining_stat(stat_slug: str, gerty):
|
||||||
|
text = []
|
||||||
|
if stat_slug == "mining_current_hash_rate":
|
||||||
|
stat = await api_get_mining_stat(stat_slug, gerty)
|
||||||
|
logger.debug(stat)
|
||||||
|
current = "{0}hash".format(si_format(stat['current'], 6, True, " "))
|
||||||
|
text.append(get_text_item_dict("Current Mining Hashrate", 20))
|
||||||
|
text.append(get_text_item_dict(current, 40))
|
||||||
|
# compare vs previous time period
|
||||||
|
difference = get_percent_difference(current=stat['current'], previous=stat['1w'])
|
||||||
|
text.append(get_text_item_dict("{0} in last 7 days".format(difference), 12))
|
||||||
|
elif stat_slug == "mining_current_difficulty":
|
||||||
|
stat = await api_get_mining_stat(stat_slug, gerty)
|
||||||
|
text.append(get_text_item_dict("Current Mining Difficulty", 20))
|
||||||
|
text.append(get_text_item_dict(format_number(stat['current']), 40))
|
||||||
|
difference = get_percent_difference(current=stat['current'], previous=stat['previous'])
|
||||||
|
text.append(get_text_item_dict("{0} since last adjustment".format(difference), 12))
|
||||||
|
# text.append(get_text_item_dict("Required threshold for mining proof-of-work", 12))
|
||||||
|
return text
|
||||||
|
|
||||||
|
async def api_get_mining_stat(stat_slug: str, gerty):
|
||||||
|
stat = ""
|
||||||
|
if stat_slug == "mining_current_hash_rate":
|
||||||
|
async with httpx.AsyncClient() as client:
|
||||||
|
r = await client.get(gerty.mempool_endpoint + "/api/v1/mining/hashrate/1m")
|
||||||
|
data = r.json()
|
||||||
|
stat = {}
|
||||||
|
stat['current'] = data['currentHashrate']
|
||||||
|
stat['1w'] = data['hashrates'][len(data['hashrates']) - 7]['avgHashrate']
|
||||||
|
elif stat_slug == "mining_current_difficulty":
|
||||||
|
async with httpx.AsyncClient() as client:
|
||||||
|
r = await client.get(gerty.mempool_endpoint + "/api/v1/mining/hashrate/1m")
|
||||||
|
data = r.json()
|
||||||
|
stat = {}
|
||||||
|
stat['current'] = data['currentDifficulty']
|
||||||
|
stat['previous'] = data['difficulty'][len(data['difficulty']) - 2]['difficulty']
|
||||||
|
return stat
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
{% extends "base.html" %} {% from "macros.jinja" import window_vars with context
|
{% extends "base.html" %} {% from "macros.jinja" import window_vars with context %} {% block page %}
|
||||||
%} {% block page %}
|
|
||||||
<div class="row q-col-gutter-md">
|
<div class="row q-col-gutter-md">
|
||||||
<div class="col-12 col-md-8 col-lg-7 q-gutter-y-md">
|
<div class="col-12 col-md-8 col-lg-7 q-gutter-y-md">
|
||||||
<q-card>
|
<q-card>
|
||||||
|
|
@ -175,7 +174,8 @@
|
||||||
label="Refresh time in seconds"
|
label="Refresh time in seconds"
|
||||||
>
|
>
|
||||||
<q-tooltip
|
<q-tooltip
|
||||||
>The amount of time in seconds between screen updates</q-tooltip
|
>The amount of time in seconds between screen updates
|
||||||
|
</q-tooltip
|
||||||
>
|
>
|
||||||
</q-input>
|
</q-input>
|
||||||
|
|
||||||
|
|
@ -190,6 +190,11 @@
|
||||||
|
|
||||||
<p>Use the toggles below to control what your Gerty will display</p>
|
<p>Use the toggles below to control what your Gerty will display</p>
|
||||||
|
|
||||||
|
<q-expansion-item
|
||||||
|
expand-separator
|
||||||
|
icon="grid_view"
|
||||||
|
label="Dashboards"
|
||||||
|
>
|
||||||
<q-toggle
|
<q-toggle
|
||||||
v-model="formDialog.data.display_preferences.dashboard"
|
v-model="formDialog.data.display_preferences.dashboard"
|
||||||
label="LNbits Dashboard"
|
label="LNbits Dashboard"
|
||||||
|
|
@ -207,17 +212,12 @@
|
||||||
></q-toggle>
|
></q-toggle>
|
||||||
|
|
||||||
<q-toggle
|
<q-toggle
|
||||||
v-model="formDialog.data.display_preferences.onchain_dashboard"
|
v-model="formDialog.data.display_preferences.dashboard_onchain"
|
||||||
label="Onchain Dashboard"
|
label="Onchain Dashboard"
|
||||||
></q-toggle>
|
></q-toggle>
|
||||||
|
|
||||||
<q-toggle
|
<q-toggle
|
||||||
v-model="formDialog.data.display_preferences.mempool_recommended_fees"
|
v-model="formDialog.data.display_preferences.dashboard_mining"
|
||||||
label="mempool.space Recommended Fees"
|
|
||||||
></q-toggle>
|
|
||||||
|
|
||||||
<q-toggle
|
|
||||||
v-model="formDialog.data.display_preferences.mining_dashboard"
|
|
||||||
label="Mining Dashboard"
|
label="Mining Dashboard"
|
||||||
></q-toggle>
|
></q-toggle>
|
||||||
|
|
||||||
|
|
@ -226,6 +226,110 @@
|
||||||
label="Lightning Network Dashboard"
|
label="Lightning Network Dashboard"
|
||||||
></q-toggle>
|
></q-toggle>
|
||||||
|
|
||||||
|
</q-expansion-item>
|
||||||
|
|
||||||
|
|
||||||
|
<q-expansion-item
|
||||||
|
expand-separator
|
||||||
|
icon="pin"
|
||||||
|
label="Single Data Points"
|
||||||
|
>
|
||||||
|
|
||||||
|
<q-expansion-item
|
||||||
|
expand-separator
|
||||||
|
icon="perm_identity"
|
||||||
|
label="LNbits Wallets"
|
||||||
|
>
|
||||||
|
<q-toggle
|
||||||
|
v-model="formDialog.data.display_preferences.lnbits_wallets_balance"
|
||||||
|
label="Show LNbits wallet balances"
|
||||||
|
></q-toggle>
|
||||||
|
|
||||||
|
</q-expansion-item>
|
||||||
|
|
||||||
|
|
||||||
|
<q-expansion-item
|
||||||
|
expand-separator
|
||||||
|
icon="link"
|
||||||
|
label="Onchain Information"
|
||||||
|
>
|
||||||
|
<q-toggle
|
||||||
|
v-model="toggleStates.onchain"
|
||||||
|
label="Toggle all"
|
||||||
|
>
|
||||||
|
<q-tooltip>Toggle all</q-tooltip>
|
||||||
|
</q-toggle>
|
||||||
|
<br>
|
||||||
|
<q-toggle
|
||||||
|
v-model="formDialog.data.display_preferences.onchain_difficulty_epoch_progress"
|
||||||
|
label="Percent of current difficulty epoch complete"
|
||||||
|
></q-toggle>
|
||||||
|
|
||||||
|
<q-toggle
|
||||||
|
v-model="formDialog.data.display_preferences.onchain_difficulty_retarget_date"
|
||||||
|
label="Estimated retarget date"
|
||||||
|
></q-toggle>
|
||||||
|
|
||||||
|
<q-toggle
|
||||||
|
v-model="formDialog.data.display_preferences.onchain_difficulty_blocks_remaining"
|
||||||
|
label="Blocks until next difficulty adjustment"
|
||||||
|
></q-toggle>
|
||||||
|
|
||||||
|
<q-toggle
|
||||||
|
v-model="formDialog.data.display_preferences.onchain_difficulty_epoch_time_remaining"
|
||||||
|
label="Estimated time until next difficulty adjustment"
|
||||||
|
></q-toggle>
|
||||||
|
</q-expansion-item>
|
||||||
|
<q-expansion-item
|
||||||
|
expand-separator
|
||||||
|
icon="psychology"
|
||||||
|
label="The Mempool"
|
||||||
|
>
|
||||||
|
<q-toggle
|
||||||
|
v-model="toggleStates.mempool"
|
||||||
|
label="Toggle all"
|
||||||
|
>
|
||||||
|
<q-tooltip>Toggle all</q-tooltip>
|
||||||
|
</q-toggle>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<q-toggle
|
||||||
|
v-model="formDialog.data.display_preferences.mempool_recommended_fees"
|
||||||
|
label="Recommended fees"
|
||||||
|
></q-toggle>
|
||||||
|
|
||||||
|
<q-toggle
|
||||||
|
v-model="formDialog.data.display_preferences.mempool_tx_count"
|
||||||
|
label="Number of transactions in the mempool"
|
||||||
|
></q-toggle>
|
||||||
|
</q-expansion-item>
|
||||||
|
|
||||||
|
<q-expansion-item
|
||||||
|
expand-separator
|
||||||
|
icon="money"
|
||||||
|
label="Mining Data"
|
||||||
|
>
|
||||||
|
<q-toggle
|
||||||
|
v-model="toggleStates.mining"
|
||||||
|
label="Toggle all"
|
||||||
|
>
|
||||||
|
<q-tooltip>Toggle all</q-tooltip>
|
||||||
|
</q-toggle>
|
||||||
|
<br>
|
||||||
|
<q-toggle
|
||||||
|
v-model="formDialog.data.display_preferences.mining_current_hash_rate"
|
||||||
|
label="Current mining hashrate"
|
||||||
|
></q-toggle>
|
||||||
|
|
||||||
|
<q-toggle
|
||||||
|
v-model="formDialog.data.display_preferences.mining_current_difficulty"
|
||||||
|
label="Current mining difficulty"
|
||||||
|
></q-toggle>
|
||||||
|
</q-expansion-item>
|
||||||
|
|
||||||
|
</q-expansion-item>
|
||||||
|
|
||||||
|
|
||||||
<div class="row q-mt-lg">
|
<div class="row q-mt-lg">
|
||||||
<q-btn
|
<q-btn
|
||||||
unelevated
|
unelevated
|
||||||
|
|
@ -270,6 +374,14 @@
|
||||||
mixins: [windowMixin],
|
mixins: [windowMixin],
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
|
toggleStates: {
|
||||||
|
fun: true,
|
||||||
|
onchain: true,
|
||||||
|
mempool: true,
|
||||||
|
mining: true,
|
||||||
|
lightning: true
|
||||||
|
},
|
||||||
|
oldToggleStates: {},
|
||||||
gertys: [],
|
gertys: [],
|
||||||
currencyOptions: [
|
currencyOptions: [
|
||||||
'USD',
|
'USD',
|
||||||
|
|
@ -475,10 +587,19 @@
|
||||||
dashboard: true,
|
dashboard: true,
|
||||||
fun_satoshi_quotes: true,
|
fun_satoshi_quotes: true,
|
||||||
fun_exchange_market_rate: true,
|
fun_exchange_market_rate: true,
|
||||||
onchain_dashboard: true,
|
dashboard_onchain: true,
|
||||||
mempool_recommended_fees: true,
|
mempool_recommended_fees: true,
|
||||||
mining_dashboard: true,
|
dashboard_mining: true,
|
||||||
lightning_dashboard: true
|
lightning_dashboard: true,
|
||||||
|
onchain: true,
|
||||||
|
onchain_difficulty_epoch_progress: true,
|
||||||
|
onchain_difficulty_retarget_date: true,
|
||||||
|
onchain_difficulty_blocks_remaining: true,
|
||||||
|
onchain_difficulty_epoch_time_remaining: true,
|
||||||
|
mempool_tx_count: true,
|
||||||
|
mining_current_hash_rate: true,
|
||||||
|
mining_current_difficulty: true,
|
||||||
|
lnbits_wallets_balance: true,
|
||||||
},
|
},
|
||||||
lnbits_wallets: [],
|
lnbits_wallets: [],
|
||||||
mempool_endpoint: "https://mempool.space",
|
mempool_endpoint: "https://mempool.space",
|
||||||
|
|
@ -627,6 +748,27 @@
|
||||||
if (this.g.user.wallets.length) {
|
if (this.g.user.wallets.length) {
|
||||||
this.getGertys()
|
this.getGertys()
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
toggleStates: {
|
||||||
|
handler(toggleStatesValue) {
|
||||||
|
// Switch all the toggles in each section to the relevant state
|
||||||
|
for (const [toggleKey, toggleValue] of Object.entries(toggleStatesValue)) {
|
||||||
|
if (this.oldToggleStates[toggleKey] !== toggleValue) {
|
||||||
|
for (const [dpKey, dpValue] of Object.entries(this.formDialog.data.display_preferences)) {
|
||||||
|
if (dpKey.indexOf(toggleKey) === 0) {
|
||||||
|
this.formDialog.data.display_preferences[dpKey] = toggleValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// This is a weird hack we have to use to get VueJS to persist the previous toggle state between
|
||||||
|
// watches. VueJS passes the old and new values by reference so when comparing objects they
|
||||||
|
// will have the same values unless we do this
|
||||||
|
this.oldToggleStates = JSON.parse(JSON.stringify(toggleStatesValue))
|
||||||
|
},
|
||||||
|
deep: true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -173,16 +173,37 @@ async def get_screen_data(screen_num: int, screens_list: dict, gerty):
|
||||||
if screen_slug == "dashboard":
|
if screen_slug == "dashboard":
|
||||||
title = gerty.name
|
title = gerty.name
|
||||||
areas = await get_dashboard(gerty)
|
areas = await get_dashboard(gerty)
|
||||||
|
if screen_slug == "lnbits_wallets_balance":
|
||||||
|
wallets = await get_lnbits_wallet_balances(gerty)
|
||||||
|
text = []
|
||||||
|
for wallet in wallets:
|
||||||
|
text.append(get_text_item_dict("{0}'s Wallet".format(wallet['name']), 20))
|
||||||
|
text.append(get_text_item_dict("{0} sats".format(format_number(wallet['balance'])), 40))
|
||||||
|
areas.append(text)
|
||||||
elif screen_slug == "fun_satoshi_quotes":
|
elif screen_slug == "fun_satoshi_quotes":
|
||||||
areas.append(await get_satoshi_quotes())
|
areas.append(await get_satoshi_quotes())
|
||||||
elif screen_slug == "fun_exchange_market_rate":
|
elif screen_slug == "fun_exchange_market_rate":
|
||||||
areas.append(await get_exchange_rate(gerty))
|
areas.append(await get_exchange_rate(gerty))
|
||||||
elif screen_slug == "onchain_dashboard":
|
elif screen_slug == "onchain_difficulty_epoch_progress":
|
||||||
|
areas.append(await get_onchain_stat(screen_slug, gerty))
|
||||||
|
elif screen_slug == "onchain_difficulty_retarget_date":
|
||||||
|
areas.append(await get_onchain_stat(screen_slug, gerty))
|
||||||
|
elif screen_slug == "onchain_difficulty_blocks_remaining":
|
||||||
|
areas.append(await get_onchain_stat(screen_slug, gerty))
|
||||||
|
elif screen_slug == "onchain_difficulty_epoch_time_remaining":
|
||||||
|
areas.append(await get_onchain_stat(screen_slug, gerty))
|
||||||
|
elif screen_slug == "dashboard_onchain":
|
||||||
title = "Onchain Data"
|
title = "Onchain Data"
|
||||||
areas = await get_onchain_dashboard(gerty)
|
areas = await get_onchain_dashboard(gerty)
|
||||||
elif screen_slug == "mempool_recommended_fees":
|
elif screen_slug == "mempool_recommended_fees":
|
||||||
areas.append(await get_mempool_stat(screen_slug, gerty))
|
areas.append(await get_mempool_stat(screen_slug, gerty))
|
||||||
elif screen_slug == "mining_dashboard":
|
elif screen_slug == "mempool_tx_count":
|
||||||
|
areas.append(await get_mempool_stat(screen_slug, gerty))
|
||||||
|
elif screen_slug == "mining_current_hash_rate":
|
||||||
|
areas.append(await get_mining_stat(screen_slug, gerty))
|
||||||
|
elif screen_slug == "mining_current_difficulty":
|
||||||
|
areas.append(await get_mining_stat(screen_slug, gerty))
|
||||||
|
elif screen_slug == "dashboard_mining":
|
||||||
title = "Mining Data"
|
title = "Mining Data"
|
||||||
areas = await get_mining_dashboard(gerty)
|
areas = await get_mining_dashboard(gerty)
|
||||||
elif screen_slug == "lightning_dashboard":
|
elif screen_slug == "lightning_dashboard":
|
||||||
|
|
@ -292,6 +313,34 @@ async def get_exchange_rate(gerty):
|
||||||
pass
|
pass
|
||||||
return text
|
return text
|
||||||
|
|
||||||
|
async def get_onchain_stat(stat_slug: str, gerty):
|
||||||
|
text = []
|
||||||
|
if (
|
||||||
|
stat_slug == "onchain_difficulty_epoch_progress" or
|
||||||
|
stat_slug == "onchain_difficulty_retarget_date" or
|
||||||
|
stat_slug == "onchain_difficulty_blocks_remaining" or
|
||||||
|
stat_slug == "onchain_difficulty_epoch_time_remaining"
|
||||||
|
):
|
||||||
|
async with httpx.AsyncClient() as client:
|
||||||
|
r = await client.get(gerty.mempool_endpoint + "/api/v1/difficulty-adjustment")
|
||||||
|
if stat_slug == "onchain_difficulty_epoch_progress":
|
||||||
|
stat = round(r.json()['progressPercent'])
|
||||||
|
text.append(get_text_item_dict("Progress through current difficulty epoch", 15))
|
||||||
|
text.append(get_text_item_dict("{0}%".format(stat), 80))
|
||||||
|
elif stat_slug == "onchain_difficulty_retarget_date":
|
||||||
|
stat = r.json()['estimatedRetargetDate']
|
||||||
|
dt = datetime.fromtimestamp(stat / 1000).strftime("%e %b %Y at %H:%M")
|
||||||
|
text.append(get_text_item_dict("Estimated date of next difficulty adjustment", 15))
|
||||||
|
text.append(get_text_item_dict(dt, 40))
|
||||||
|
elif stat_slug == "onchain_difficulty_blocks_remaining":
|
||||||
|
stat = r.json()['remainingBlocks']
|
||||||
|
text.append(get_text_item_dict("Blocks remaining until next difficulty adjustment", 15))
|
||||||
|
text.append(get_text_item_dict("{0}".format(format_number(stat)), 80))
|
||||||
|
elif stat_slug == "onchain_difficulty_epoch_time_remaining":
|
||||||
|
stat = r.json()['remainingTime']
|
||||||
|
text.append(get_text_item_dict("Blocks remaining until next difficulty adjustment", 15))
|
||||||
|
text.append(get_text_item_dict(get_time_remaining(stat / 1000, 4), 20))
|
||||||
|
return text
|
||||||
|
|
||||||
async def get_onchain_dashboard(gerty):
|
async def get_onchain_dashboard(gerty):
|
||||||
areas = []
|
areas = []
|
||||||
|
|
@ -440,3 +489,30 @@ async def get_mempool_stat(stat_slug: str, gerty):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return text
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
def get_date_suffix(dayNumber):
|
||||||
|
if 4 <= dayNumber <= 20 or 24 <= dayNumber <= 30:
|
||||||
|
return "th"
|
||||||
|
else:
|
||||||
|
return ["st", "nd", "rd"][dayNumber % 10 - 1]
|
||||||
|
|
||||||
|
def get_time_remaining(seconds, granularity=2):
|
||||||
|
intervals = (
|
||||||
|
# ('weeks', 604800), # 60 * 60 * 24 * 7
|
||||||
|
('days', 86400), # 60 * 60 * 24
|
||||||
|
('hours', 3600), # 60 * 60
|
||||||
|
('minutes', 60),
|
||||||
|
('seconds', 1),
|
||||||
|
)
|
||||||
|
|
||||||
|
result = []
|
||||||
|
|
||||||
|
for name, count in intervals:
|
||||||
|
value = seconds // count
|
||||||
|
if value:
|
||||||
|
seconds -= value * count
|
||||||
|
if value == 1:
|
||||||
|
name = name.rstrip('s')
|
||||||
|
result.append("{} {}".format(round(value), name))
|
||||||
|
return ', '.join(result[:granularity])
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue