# @name Fuel Prices # @desc Cheapest nearby price, brand and street for one fuel type (tankerkoenig.de) # @author Hank_the_Tank / Claude # @version 1.5 # @config apikey text "API key" default="YOUR-API-KEY" help="Free key from creativecommons.tankerkoenig.de" # @config lat text "Latitude" default="52.5200" # @config lon text "Longitude" default="13.4050" # @config radius number "Radius" default=5 min=1 max=25 unit=km # @config fuel select "Fuel" default=diesel options=diesel,e5,e10 # @config every number "Refresh" default=10 min=5 max=60 unit=min # @config tint color "Price color" default=#00FF00 # @config icon text "Icon ID" default="" import string import json class FuelPrice var url, find # request URL and search needle, built from settings var ic, tint # icon name and price colour var price, brand, street # last known values for the cheapest station var label # the [text, color] pieces draw() paints var period, ticks, in_flight # loop() pacing def fmt() # builds the coloured display pieces if self.price == nil return [["...", 0x666666]] end var b = self.brand == nil ? "" : self.brand var s = self.street == nil ? "" : self.street return [[string.format("%.3f", self.price) + "€", self.tint], [" | " + b + " | " + s, 0xFFFFFF]] end def init() self.ic = store.get("icon") self.tint = store.get("tint") self.url = "https://creativecommons.tankerkoenig.de/json/list.php?lat=" + store.get("lat") + "&lng=" + store.get("lon") + "&rad=" + str(store.get("radius")) + "&sort=price&type=" + store.get("fuel") + "&apikey=" + store.get("apikey") self.find = "{\"id\":\"" # start of the first (cheapest) station object self.period = store.get("every") * 60 # loop() runs ~1x/s self.price = store.get("price") # survive a reboot self.brand = store.get("brand") self.street = store.get("street") self.label = self.fmt() self.ticks = 0 self.in_flight = false end def on_body(body, status) self.in_flight = false if body == nil log("FuelPrices: no data (status " + str(status) + ") - check API key / coordinates") return end var mp = re.search("\"price\":([0-9]+\\.[0-9]+)", body) if mp == nil return end var p = num(mp[1]) if p == nil return end var mb = re.search("\"brand\":\"([^\"]*)\"", body) var ms = re.search("\"street\":\"([^\"]*)\"", body) # re-wrap each raw JSON string piece and let json.load decode escapes (umlauts etc.) self.price = p self.brand = mb == nil ? "" : json.load("[\"" + mb[1] + "\"]")[0] self.street = ms == nil ? "" : json.load("[\"" + ms[1] + "\"]")[0] self.label = self.fmt() # rebuild the coloured line store.set("price", p) # only keep it once it is good store.set("brand", self.brand) store.set("street", self.street) 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.find, 'keep': 480}) end end self.ticks -= 1 end def draw() clear() if !icon(self.ic, 0, 0) # no icon set, or unknown to the device rect_fill(2, 1, 4, 6, 0x555555) # fallback: a small pump shape rect_fill(1, 0, 2, 1, 0x555555) line(6, 2, 7, 2, 0x555555) line(7, 2, 7, 5, 0x555555) end scroll_text(9, 6, width() - 9, self.label, 0xFFFFFF) end def on_button(btn) if btn == "select" self.ticks = 0 end # force an immediate refresh end end return FuelPrice()