# @name NINA Warnung # @desc Aktuelle Bevoelkerungsschutz-Warnungen (BBK) fuer einen Landkreis # @author Hank_the_Tank / Codex # @version 1.1 # @config ars text "Kreisschluessel (AGS)" default="" maxlen=5 help="5-stellig, z.B. 05913 fuer Bochum - Liste: xrepository.de Regionalschluessel" # @config every number "Aktualisierung" default=10 min=1 max=60 unit=min # @config min_sev select "Ab Warnstufe" default=Minor options=Minor,Moderate,Severe,Extreme # @config notify bool "Bei neuer Warnung benachrichtigen" default=true # @config sound bool "Signalton ueber Buzzer" default=true # @config always bool "Auch ohne Warnung anzeigen" default=true help="Gruener Haken, wenn nichts vorliegt - hilfreich zum Testen" class NinaWarnung var ars, url, period, sevmin, notifyon, soundon, always, err var count, sev, head, color, lastid, firstrun, melody var ticks, busy def init() self.ars = store.get("ars") self.err = self.ars == "" self.url = "https://warnung.bund.de/api31/dashboard/" + self.ars + "0000000.json" self.period = store.get("every") * 60 self.sevmin = self.rank(store.get("min_sev")) self.notifyon = store.get("notify") self.soundon = store.get("sound") self.always = store.get("always") self.melody = "alarm:d=8,o=6,b=180:c,a5,c,a5,c,a5,c,a5" self.count = store.get("count", 0) self.sev = store.get("sev", "") self.head = store.get("head", "") self.color = self.color_for(self.sev) var li = store.get("lastid") self.firstrun = li == nil self.lastid = li == nil ? "" : li self.ticks = self.err ? self.period : 15 self.busy = false end # Rangfolge der CAP-Warnstufen, fuer den Schwellwertvergleich def rank(s) if s == "Extreme" return 4 end if s == "Severe" return 3 end if s == "Moderate" return 2 end if s == "Minor" return 1 end return 0 end def color_for(s) if s == "Extreme" return 0xCC00CC end if s == "Severe" return 0xFF0000 end if s == "Moderate" return 0xFF8800 end if s == "Minor" return 0xFFCC00 end return 0x00CC44 end def on_body(body, status) self.busy = false if body == nil return end var hits = re.matchall("\"headline\":\"", body) var n = size(hits) self.count = n if n == 0 self.sev = "" self.head = "" self.color = self.color_for("") store.set("count", 0) store.set("sev", "") store.set("head", "") return end var sm = re.search("\"severity\":\"(\\w+)\"", body) var hm = re.search("\"headline\":\"([^\"]*)\"", body) if sm == nil || hm == nil return end self.sev = sm[1] self.head = hm[1] self.color = self.color_for(self.sev) var im = re.search("\"id\":\"([^\"]*)\"", body) var id = im == nil ? "" : im[1] if !self.firstrun && self.notifyon && id != self.lastid && self.rank(self.sev) >= self.sevmin var spec = {"text": self.head, "textColor": self.color} if self.soundon spec["soundRtttl"] = self.melody if self.sev == "Extreme" spec["soundLoop"] = true spec["hold"] = true end end notify(spec) end self.firstrun = false self.lastid = id store.set("count", self.count) store.set("sev", self.sev) store.set("head", self.head) store.set("lastid", self.lastid) end def loop() if self.err return end if self.ticks <= 0 && !self.busy self.ticks = self.period self.busy = true http.get(self.url, / b, st -> self.on_body(b, st)) end self.ticks -= 1 end def should_show() if self.err return true end if self.count > 0 && self.rank(self.sev) >= self.sevmin return true end return self.always end def draw() clear() if self.err text(1, 6, "ARS?", 0xFF8800) return end if self.count == 0 || self.rank(self.sev) < self.sevmin circle_fill(4, 4, 3, 0x00CC44) text(9, 6, "OK", 0x00CC44) return end var bcol = self.color if self.sev == "Extreme" && (now_ms() % 600) < 300 bcol = 0xFFFFFF end rect_fill(0, 0, 8, 8, bcol) text(3, 6, "!", 0x000000) scroll_text(9, 6, width() - 9, self.head, 0xFFFFFF) end def on_button(btn) if btn == "select" self.ticks = 0 end if btn == "right" && self.soundon notify({"text": "Testton", "textColor": 0xFFCC00, "soundRtttl": self.melody}) end end end return NinaWarnung()