Files
bitcoin-ticker-pi/cmd/rpi/main.go
T

174 lines
4.1 KiB
Go

package main
import (
"context"
"fmt"
"image/color"
"log"
"net/http"
"sync"
"time"
"git.dvdt.dev/david/bitcoin-ticker-pi/display"
"git.dvdt.dev/david/bitcoin-ticker-pi/fonts"
rgbmatrix "git.dvdt.dev/david/bitcoin-ticker-pi/go-rpi-rgb-led-matrix"
"git.dvdt.dev/david/bitcoin-ticker-pi/mempool"
)
const (
RefreshRateHz = 1
MempoolURL = "mempool.space"
)
func main() {
cfg := rgbmatrix.DefaultConfig
cfg.Rows = 32
cfg.Cols = 64
m, _ := rgbmatrix.NewRGBLedMatrix(&cfg)
c := rgbmatrix.NewCanvas(m)
d := display.New(c,
display.NewSlot(9, 5, 4, 0, 0),
display.NewSlot(5, 5, 4, 44, 0),
display.NewSlot(7, 13, 8, 5, 9),
display.NewSlot(12, 5, 4, 7, 27),
)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
ticker := time.NewTicker(time.Second / RefreshRateHz)
tdone := make(chan struct{})
mdone := make(chan struct{})
msgs := make(chan mempool.Message)
errs := make(chan error)
mp := mempool.New(MempoolURL, &http.Client{
Timeout: 5 * time.Second,
})
err := mp.Init()
if err != nil {
log.Fatal(err)
}
currentBlockHeight, err := mp.CurrentBlockHeight()
if err != nil {
log.Fatal(err)
}
highfee, medfee, lowfee, err := mp.CurrentFees()
if err != nil {
log.Fatal(err)
}
var blockHeight int
blockHeightMutex := &sync.Mutex{}
var fees mempool.Fees
feesMutex := &sync.Mutex{}
var price int
priceMutex := &sync.Mutex{}
blockHeight = currentBlockHeight
fees.FastestFee = highfee
fees.HalfHourFee = medfee
fees.HourFee = lowfee
go mp.Listen(ctx, msgs, errs, mdone)
go func() {
for {
select {
case m := <-msgs:
fmt.Printf("%+v\n", m)
if m.Fees != nil {
feesMutex.Lock()
fees = *m.Fees
feesMutex.Unlock()
}
if m.Block != nil {
blockHeightMutex.Lock()
blockHeight = int(m.Block.Height)
blockHeightMutex.Unlock()
}
if m.Conversions != nil {
priceMutex.Lock()
price = m.Conversions.USD
priceMutex.Unlock()
}
}
}
}()
for {
select {
case <-tdone:
return
case <-ticker.C:
d.Clear()
d.Render()
err = updateSlots(d, price, blockHeight, fees.HourFee, fees.HalfHourFee, fees.FastestFee)
if err != nil {
log.Fatal(err)
}
}
}
}
func updateSlots(d *display.Display, price, height, lfee, mfee, hfee int) error {
d.Clear()
var priceSegments []display.Segment
priceSegments = append(priceSegments, display.Segment{Text: "dollar", Color: fonts.Green})
priceSegments = append(priceSegments, strToDisplaySegments(fmt.Sprintf("%d", price), fonts.White)...)
err := d.UpdateTopLeft(priceSegments)
if err != nil {
return err
}
var moscowTimeSegments []display.Segment
moscowTime := 0
if price > 0 {
moscowTime = 100000000 / price
}
moscowTimeSegments = append(moscowTimeSegments, display.Segment{Text: "satoshi", Color: fonts.Orange})
moscowTimeSegments = append(moscowTimeSegments, strToDisplaySegments(fmt.Sprintf("%d", moscowTime), fonts.White)...)
err = d.UpdateTopRight(moscowTimeSegments)
if err != nil {
return err
}
var heightSegments []display.Segment
heightSegments = append(heightSegments, display.Segment{Text: "height", Color: fonts.Blue})
heightSegments = append(heightSegments, strToDisplaySegments(fmt.Sprintf("%d", height), fonts.White)...)
err = d.UpdateMain(heightSegments)
if err != nil {
return err
}
var feeSegments []display.Segment
feeSegments = append(feeSegments, display.Segment{Text: "low", Color: fonts.Green})
feeSegments = append(feeSegments, strToDisplaySegments(fmt.Sprintf("%d", lfee), fonts.White)...)
feeSegments = append(feeSegments, display.Segment{Text: "medium", Color: fonts.Orange})
feeSegments = append(feeSegments, strToDisplaySegments(fmt.Sprintf("%d", mfee), fonts.White)...)
feeSegments = append(feeSegments, display.Segment{Text: "high", Color: fonts.Red})
feeSegments = append(feeSegments, strToDisplaySegments(fmt.Sprintf("%d", hfee), fonts.White)...)
err = d.UpdateBottom(feeSegments)
if err != nil {
return err
}
return d.Render()
}
func strToDisplaySegments(s string, c color.RGBA) []display.Segment {
var segs []display.Segment
for _, r := range s {
segs = append(segs, display.Segment{Text: string(r), Color: c})
}
return segs
}