# @name Bitcoin # @desc Bitcoin price via CoinGecko (no API key needed) # @author RobG # @version 1.0 # @config currency select "Currency" default=usd options=usd,eur # @config every number "Refresh" default=5 min=1 max=60 unit=min # @config color color "Text color" default=#FFFFFF # @config ic text "Icon" default="12460" help="Icon name/ID from the device icon folder. Missing = orange B" # @config compact bool "Short format (114.1K)" default=false class Bitcoin var url, needle, period # built from the settings in init() var color, ic, compact var price # last known price, nil until the first success var label # the finished string draw() paints var ticks, in_flight # countdown of loop() calls; request outstanding var age # seconds since the last successful fetch def fmt(v) if self.compact && v >= 10000 return str(round(v / 1000.0, 1)) + "K" end return str(round(v)) end def init() var cur = str(store.get("currency")) self.url = "https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=" + cur self.needle = "\"" + cur + "\":" self.period = num(store.get("every"), 5) * 60 self.color = store.get("color") self.ic = store.get("ic") self.compact = store.get("compact") == true self.price = store.get("price") # survives a reboot: shows instantly self.label = self.price == nil ? nil : self.fmt(self.price) self.ticks = 0 self.in_flight = false self.age = 0 end def on_body(body, status) self.in_flight = false if body == nil return end # one check, every failure var m = re.search("([0-9][0-9.]*)", body) # body starts at "usd": thanks to find if m == nil return end var v = num(m[1]) if v == nil return end self.price = v self.label = self.fmt(v) self.age = 0 store.set("price", v) # only once it is good end def loop() if self.ticks <= 0 self.ticks = self.period if !self.in_flight self.in_flight = true http.get(self.url, / b, st -> self.on_body(b, st), {'find': self.needle, 'keep': 32}) end end self.ticks -= 1 self.age += 1 end def should_show() # nothing fetched yet, or the data has gone stale: skip our turn return self.label != nil && self.age < self.period * 3 end def draw() clear() if !icon(self.ic, 0, 0) text(2, 6, "B", 0xF7931A) # fallback when the icon is missing end if self.label != nil scroll_text(9, 6, width() - 9, self.label, self.color) end end end return Bitcoin()