diff --git a/apis/nina/main.go b/apis/nina/main.go new file mode 100644 index 0000000..9b02686 --- /dev/null +++ b/apis/nina/main.go @@ -0,0 +1,89 @@ +package nina + +import ( + "ArinDash/config" + "encoding/json" + "io" + "log" + "net/http" +) + +const apiBaseURL = "https://warnung.bund.de/api31" + +type configFile struct { + Nina ninaConfig +} + +type ninaConfig struct { + GebietsCode string +} + +type Warning struct { + Id string `json:"id"` + Identifier string `json:"identifier"` + Sender string `json:"sender"` + Sent string `json:"sent"` + Status string `json:"status"` + MsgType string `json:"msgType"` + Scope string `json:"scope"` + Code []string `json:"code"` + Reference string `json:"reference"` + Info []Info `json:"info"` +} + +type Info struct { + Language string `json:"language"` + Category []string `json:"category"` + Event string `json:"event"` + Urgency string `json:"urgency"` + Severity string `json:"severity"` + Expires string `json:"expires"` + Headline string `json:"headline"` + Description string `json:"description"` +} + +func FetchWarnings() []Warning { + cfg := &configFile{} + config.LoadConfig(cfg) + client := &http.Client{} + + req, err := http.NewRequest("GET", apiBaseURL+"/dashboard/"+cfg.Nina.GebietsCode+".json", nil) + if err != nil { + panic(err) + } + resp, err := client.Do(req) + if err != nil { + log.Fatal(err) + } + defer resp.Body.Close() + respBody, err := io.ReadAll(resp.Body) + if err != nil { + log.Fatal(err) + } + + warnings := make([]Warning, 0) + err = json.Unmarshal(respBody, &warnings) + if err != nil { + log.Fatal(err) + } + result := make([]Warning, 0) + for _, warning := range warnings { + req, err := http.NewRequest("GET", apiBaseURL+"/warnings/"+warning.Id+".json", nil) + if err != nil { + panic(err) + } + resp, err := client.Do(req) + if err != nil { + log.Fatal(err) + } + defer resp.Body.Close() + respBody, err := io.ReadAll(resp.Body) + if err != nil { + log.Fatal(err) + } + warning := Warning{} + err = json.Unmarshal(respBody, &warning) + result = append(result, warning) + } + return result +} diff --git a/config_template.toml b/config_template.toml index f8a7886..9460894 100644 --- a/config_template.toml +++ b/config_template.toml @@ -13,3 +13,7 @@ Password = "YourPassword" #ID from http://bulk.openweathermap.org/sample/city.list.json.gz; unzip the gz file and find your city LocationId = "0000000" ApiKey = "YourApiKey" + +[nina] +#Code from https://www.xrepository.de/api/xrepository/urn:de:bund:destatis:bevoelkerungsstatistik:schluessel:rs_2021-07-31/download/Regionalschl_ssel_2021-07-31.json +gebietsCode = "000000000000" diff --git a/main.go b/main.go index 6aae481..0a2a105 100644 --- a/main.go +++ b/main.go @@ -43,12 +43,14 @@ func initWidgets(ctx context.Context, term *tcell.Terminal) { widgets.New("HTTPProber", widgets.HTTPProber()), widgets.New("PiHole", widgets.PiholeStats()), widgets.New("PiHoleBlocked", widgets.PiholeBlocked()), + widgets.New("NinaWarnings", widgets.NinaWarnings()), ) } func layout() []container.Option { builder := grid.New() builder.Add( + grid.ColWidthFixed(84, grid.RowHeightFixed(44, grid.Widget(widgets.Get["Wifi"], @@ -56,7 +58,7 @@ func layout() []container.Option { container.Border(linestyle.Light), container.BorderColor(cell.ColorWhite)), ), - grid.RowHeightFixed(44, + grid.RowHeightFixed(46, grid.Widget(widgets.Get["NetworkDevices"], container.BorderTitle("Network Devices"), container.Border(linestyle.Light), @@ -66,56 +68,76 @@ func layout() []container.Option { grid.Widget(widgets.Get["empty"]), ), ), - grid.ColWidthPerc(20, - grid.RowHeightFixed(8, - grid.Widget(widgets.Get["Clock"], - container.AlignHorizontal(align.HorizontalCenter), - container.BorderTitle("Time"), - container.Border(linestyle.Light), - container.BorderColor(cell.ColorWhite), + + grid.ColWidthPerc(58, + grid.RowHeightFixed(44, + grid.ColWidthFixed(40, + grid.RowHeightFixed(8, + grid.Widget(widgets.Get["Clock"], + container.AlignHorizontal(align.HorizontalCenter), + container.BorderTitle("Time"), + container.Border(linestyle.Light), + container.BorderColor(cell.ColorWhite), + ), + ), + grid.RowHeightFixed(12, + grid.Widget(widgets.Get["PiHole"], + container.BorderTitle("pi-hole"), + container.Border(linestyle.Light), + container.BorderColor(cell.ColorWhite), + ), + ), + grid.RowHeightFixed(40, + grid.Widget(widgets.Get["PiHoleBlocked"], + container.BorderTitle("pi-hole (Blocked Percent)"), + container.Border(linestyle.Light), + container.BorderColor(cell.ColorWhite), + ), + ), + grid.RowHeightFixed(85, + grid.Widget(widgets.Get["empty"]), + ), + ), + + grid.ColWidthFixed(26, + grid.RowHeightFixed(20, + grid.Widget(widgets.Get["Calendar"], + container.BorderTitle("Calendar"), + container.Border(linestyle.Light), + container.BorderColor(cell.ColorWhite)), + ), + grid.RowHeightFixed(25, + grid.Widget(widgets.Get["empty"]), + ), + ), + + grid.ColWidthFixed(25, + grid.RowHeightFixed(20, + grid.Widget(widgets.Get["Weather"], + container.BorderTitle("Weather"), + container.Border(linestyle.Light), + container.BorderColor(cell.ColorWhite), + ), + ), + grid.RowHeightFixed(85, + grid.Widget(widgets.Get["empty"]), + ), ), ), - grid.RowHeightFixed(12, - grid.Widget(widgets.Get["PiHole"], - container.BorderTitle("pi-hole"), - container.Border(linestyle.Light), - container.BorderColor(cell.ColorWhite), - ), - ), - grid.RowHeightFixed(24, - grid.Widget(widgets.Get["PiHoleBlocked"], - container.BorderTitle("pi-hole (Blocked Percent)"), - container.Border(linestyle.Light), - container.BorderColor(cell.ColorWhite), - ), - ), - grid.RowHeightPerc(85, - grid.Widget(widgets.Get["empty"]), - ), - ), - grid.ColWidthPerc(13, grid.RowHeightFixed(20, - grid.Widget(widgets.Get["Calendar"], - container.BorderTitle("Calendar"), - container.Border(linestyle.Light), - container.BorderColor(cell.ColorWhite)), - ), - grid.RowHeightPerc(25, - grid.Widget(widgets.Get["empty"]), - ), - ), - grid.ColWidthPerc(25, - grid.RowHeightFixed(20, - grid.Widget(widgets.Get["Weather"], - container.BorderTitle("Weather"), - container.Border(linestyle.Light), - container.BorderColor(cell.ColorWhite), + grid.RowHeightFixed(25, + grid.Widget(widgets.Get["empty"]), + ), + grid.RowHeightFixed(20, + grid.Widget(widgets.Get["NinaWarnings"], + container.BorderTitle("BBK Warnings"), + container.Border(linestyle.Light), + container.BorderColor(cell.ColorWhite), + ), ), ), - grid.RowHeightPerc(25, - grid.Widget(widgets.Get["empty"]), - ), ), + grid.ColWidthPerc(35, grid.RowHeightPerc(20, grid.Widget(widgets.Get["HTTPProber"], diff --git a/widgets/ninaWarnings.go b/widgets/ninaWarnings.go new file mode 100644 index 0000000..7604053 --- /dev/null +++ b/widgets/ninaWarnings.go @@ -0,0 +1,63 @@ +package widgets + +import ( + "ArinDash/apis/nina" + "ArinDash/util" + "context" + "fmt" + "regexp" + "time" + + "github.com/mum4k/termdash/cell" + "github.com/mum4k/termdash/terminal/terminalapi" + "github.com/mum4k/termdash/widgetapi" + "github.com/mum4k/termdash/widgets/text" +) + +type NinaWarningsOptions struct { +} + +func NinaWarnings() NinaWarningsOptions { + widgetOptions["NinaWarningsOptions"] = createNinaWarnings + return NinaWarningsOptions{} +} + +func createNinaWarnings(ctx context.Context, _ terminalapi.Terminal, _ interface{}) widgetapi.Widget { + widget := util.PanicOnErrorWithResult(text.New(text.WrapAtWords())) + + go util.Periodic(ctx, 1*time.Minute, func() error { + warnings := nina.FetchWarnings() + widget.Reset() + for _, warning := range warnings { + for _, info := range warning.Info { + var options []cell.Option + if info.Severity == "Moderate" { + options = append(options, cell.FgColor(cell.ColorRed)) + } else if info.Severity == "Minor" { + options = append(options, cell.FgColor(cell.ColorYellow)) + } else if info.Severity == "Fine" { + options = append(options, cell.FgColor(cell.ColorGray)) + } else if info.Severity == "Cancel" { + options = append(options, cell.FgColor(cell.ColorGreen)) + } else { + options = append(options, cell.FgColor(cell.ColorRed)) + options = append(options, cell.Blink()) + } + if err := widget.Write(fmt.Sprintf("%s\n\n", info.Headline), text.WriteCellOpts(append(options, cell.Bold())...)); err != nil { + return err + } + if err := widget.Write(fmt.Sprintf("%s\n\n\n", removeElements(info.Description)), text.WriteCellOpts(options...)); err != nil { + return err + } + } + } + return nil + }) + + return widget +} +func removeElements(input string) string { + // Pattern to match content or + re := regexp.MustCompile(`.*|
| `) + return re.ReplaceAllString(input, "") +}