Skip to content

Instantly share code, notes, and snippets.

@ilyasst
Created March 26, 2026 05:06
Show Gist options
  • Select an option

  • Save ilyasst/2dd6dcb74b1c6dd29875ef8ddda01d36 to your computer and use it in GitHub Desktop.

Select an option

Save ilyasst/2dd6dcb74b1c6dd29875ef8ddda01d36 to your computer and use it in GitHub Desktop.
node_utxoracle_meshtastic.py
import requests
import datetime
import subprocess
import re
import zoneinfo
import os
RPC_USER = "your_rpc_user"
RPC_PASS = "your_rpc_password"
RPC_HOST = "192.168.x.x"
RPC_PORT = 9332
RPC_URL = f"http://{RPC_USER}:{RPC_PASS}@{RPC_HOST}:{RPC_PORT}/"
LAST_PRICE_FILE = os.path.expanduser("~/.last_btc_price")
def rpc_call(method, params=[]):
payload = {
"jsonrpc": "1.0",
"id": "python_script",
"method": method,
"params": params
}
response = requests.post(RPC_URL, json=payload)
response.raise_for_status()
res_json = response.json()
if res_json.get("error"):
raise Exception(f"RPC Error: {res_json['error']}")
return res_json['result']
def get_montreal_time():
tz = zoneinfo.ZoneInfo("America/Montreal")
return datetime.datetime.now(tz).strftime("%H:%M")
def get_utxoracle_price():
result = subprocess.run(
["python", "/path/to/UTXOracle/UTXOracle.py"],
capture_output=True,
text=True
)
match = re.search(r"price:\s*\$([\d,]+)", result.stdout)
if match:
return int(match.group(1).replace(",", ""))
return None
def get_fee(target):
try:
res = rpc_call("estimatesmartfee", [target])
fee_btc_per_kb = res.get("feerate", 0)
if fee_btc_per_kb <= 0:
return 1
sats_per_vbyte = (fee_btc_per_kb * 100_000_000) / 1000
return max(1, round(sats_per_vbyte))
except Exception:
return 1
def main():
try:
height = rpc_call("getblockcount")
except Exception as e:
print(f"Error fetching height: {e}")
return
time_str = get_montreal_time()
price = get_utxoracle_price()
if price:
# Check if price changed by >= $1000 since last run
if os.path.exists(LAST_PRICE_FILE):
try:
with open(LAST_PRICE_FILE, "r") as f:
last_price = int(f.read().strip())
if abs(price - last_price) < 1000:
print(f"Current price (${price}) changed by less than $1000 from last broadcast (${last_price}). Skipping message.")
return
except Exception as e:
print(f"Error reading {LAST_PRICE_FILE}: {e}")
# Save new price
try:
with open(LAST_PRICE_FILE, "w") as f:
f.write(str(price))
except Exception as e:
print(f"Error writing to {LAST_PRICE_FILE}: {e}")
moscow_time = round(100_000_000 / price)
price_str = f"${price:,}".replace(",", " ")
else:
moscow_time = "N/A"
price_str = "N/A"
try:
mempool_info = rpc_call("getmempoolinfo")
txs = mempool_info.get('size', 0)
except Exception:
txs = 0
low = get_fee(144)
mid = get_fee(18)
high = get_fee(2)
avg_time_str = "N/A"
diff_arrow = ""
try:
current_hash = rpc_call("getblockhash", [height])
current_block = rpc_call("getblock", [current_hash, 1])
current_time = current_block['time']
# Calculate the last difficulty adjustment block
# Difficulty adjusts every 2016 blocks. The new epoch starts at height - (height % 2016)
last_diff_height = height - (height % 2016)
# We need at least 1 block in the new epoch to calculate an average
if height > last_diff_height:
past_hash = rpc_call("getblockhash", [last_diff_height])
past_block = rpc_call("getblock", [past_hash, 1])
past_time = past_block['time']
blocks_passed = height - last_diff_height
avg_time_sec = (current_time - past_time) / blocks_passed
mins = int(avg_time_sec // 60)
secs = int(avg_time_sec % 60)
avg_time_str = f"{mins}m{secs:02d}s"
# If average time > 10 mins (600s), diff goes down. Otherwise up.
if avg_time_sec > 600:
diff_arrow = "⬇️"
else:
diff_arrow = "⬆️"
else:
avg_time_str = "0m00s"
diff_arrow = "-"
except Exception as e:
print(f"Error calculating avg block time: {e}")
height_str = f"{height:,}".replace(",", " ")
# Format message exactly as requested
message = f"{height_str}, {time_str}\n"
message += f"{price_str}, {moscow_time}\n"
message += f"{low}/{mid}/{high}, {txs} txs\n"
message += f"{avg_time_str}, Diff {diff_arrow}"
print("Sending message:")
print(message)
print("----------------")
# Send via meshtastic
subprocess.run([
"meshtastic",
"--sendtext", message,
"--ch-index", "1",
"--port", "/dev/ttyUSB0"
])
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment