From 0788b8eafc300d47b33a4238103995140f14fb99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Malte=20M=C3=BCnch?= Date: Wed, 12 Feb 2020 01:37:09 +0100 Subject: [PATCH] joa dateien geadded --- create_map/README.md | 15 ++ create_map/get_coordinates.py | 142 +++++++++++ show_leds/show_leds.ino | 79 ++++++ spacepanel_aggregator/go.mod | 9 + spacepanel_aggregator/go.sum | 47 ++++ spacepanel_aggregator/httppoll.go | 76 ++++++ spacepanel_aggregator/setup.go | 86 +++++++ .../spacepanel_aggregator/cmd.go | 44 ++++ .../spacepanel_aggregator/conf.yml | 184 ++++++++++++++ spacepanel_aggregator/types.go | 239 ++++++++++++++++++ 10 files changed, 921 insertions(+) create mode 100644 create_map/README.md create mode 100755 create_map/get_coordinates.py create mode 100644 show_leds/show_leds.ino create mode 100644 spacepanel_aggregator/go.mod create mode 100644 spacepanel_aggregator/go.sum create mode 100644 spacepanel_aggregator/httppoll.go create mode 100644 spacepanel_aggregator/setup.go create mode 100644 spacepanel_aggregator/spacepanel_aggregator/cmd.go create mode 100644 spacepanel_aggregator/spacepanel_aggregator/conf.yml create mode 100644 spacepanel_aggregator/types.go diff --git a/create_map/README.md b/create_map/README.md new file mode 100644 index 0000000..f5adb04 --- /dev/null +++ b/create_map/README.md @@ -0,0 +1,15 @@ +# create_map +Dieses kleine Repo beinhaltet ein Pythonskript welches aus dem Spacedirectory +spaces auswählt und sie dann 1. auf einer SVG-Karte darstellt die man dann +schön Lasercuttern kann und 2. in eine conf.yml tut die dann vom +spacepanel_aggregator genutzt werden kann. + +Wenn ich meinen Code noch halbwegs richtig verstehe läuft das Programm +folgendermaßen: + +1. Alle Spaces aus dem Spacedirectory runterladen +2. Check auf Erreichbarkeit des API Endpoints +3. Im API-Output checken ob der Doorstatus sinnvolle Dinge ausgibt +4. Checken ob der Space in Germany liegt +5. Spaces die zu nah aneinander liegen werden automatically gemerged (zum + Beispiel in Berlin oder Hamburg) diff --git a/create_map/get_coordinates.py b/create_map/get_coordinates.py new file mode 100755 index 0000000..4bbf235 --- /dev/null +++ b/create_map/get_coordinates.py @@ -0,0 +1,142 @@ +#!/usr/bin/python +import requests +import json +import pickle +import os.path +import svgwrite +import math +import sys +import concurrent.futures + +URL = "https://directory.spaceapi.io/" +NORTHERNMOST = 55.05 +EASTERNMOST = 15.033333 +SOUTHERNMOST = 47.270108 +WESTERNMOST = 5.866667 +threshold = 0.10 +YSPAN = NORTHERNMOST - SOUTHERNMOST +XSPAN = EASTERNMOST - WESTERNMOST +locations = {} +ignorelist = ["Chaostreff Salzburg", "DevLoL", "CCC Basel", "Chaostreff Zürich", + "ChaosStuff", "Level2", "Bastli", "Maakplek", "TkkrLab", "Hack42", + "Hackerspace Nijmegen", "TDvenlo", "ACKspace"] + + +def dist(n1, n2): + y = n1[0] - n2[0] + x = n1[1] - n2[1] + return math.sqrt(math.pow(x, 2) + math.pow(y, 2)) + + +def conflict(targetlist, node): + returner = None + for element in targetlist: + if dist(node, targetlist[element]) < threshold: + returner = element + continue + return returner + + +def merge(n1, n2): + lat = (n1[0] + n2[0]) / 2 + lon = (n1[1] + n2[1]) / 2 + returner = [] + returner.append(lat) + returner.append(lon) + for i in range(2, len(n1)): + returner.append(n1[i]) + for i in range(2, len(n2)): + returner.append(n2[i]) + return returner + + +def get_space_location(space): + try: + spacerequest = requests.get(url=data[space], timeout=1) + spacedata = spacerequest.json() + except requests.exceptions.RequestException as _: + return + except json.JSONDecodeError as _: + return + if "location" in spacedata: + if "lat" in spacedata["location"]: + lat = spacedata["location"]["lat"] + lon = spacedata["location"]["lon"] + return [float(lat), float(lon), data[space]] + + +if os.path.isfile('locations.bin'): + print("using offline data...", file=sys.stderr) + with open("locations.bin", "rb") as f: + locations = pickle.load(f) +else: + print("offline data not available, downloading...", file=sys.stderr) + r = requests.get(url=URL) + data = r.json() + with concurrent.futures.ThreadPoolExecutor(max_workers=16) as executor: + futures = {} + for space in data: + futures[space] = executor.submit(get_space_location, space) + for space in data: + location = futures[space].result() + if location: + locations[space] = location + print("done loading space data", file=sys.stderr) + + for space in locations: + print(space + " " + str(locations[space])) + with open("locations.bin", "wb") as f: + pickle.dump(locations, f, pickle.HIGHEST_PROTOCOL) + +print("Removing non-german points...", file=sys.stderr) +german_locations = locations.copy() +for space in locations: + if locations[space][0] > NORTHERNMOST: + del german_locations[space] + elif locations[space][0] < SOUTHERNMOST: + del german_locations[space] + elif locations[space][1] < WESTERNMOST: + del german_locations[space] + elif locations[space][1] > EASTERNMOST: + del german_locations[space] + +for space in ignorelist: + del german_locations[space] + +finallist = {} +while german_locations: + n1 = next(iter(german_locations)) + conflictnode = conflict(finallist, german_locations[n1]) + if conflictnode == None: + finallist.update({n1: german_locations[n1]}) + del german_locations[n1] + else: + mergenode = merge(german_locations[n1], finallist[conflictnode]) + del german_locations[n1] + del finallist[conflictnode] + german_locations.update( + {"MERGED: " + n1 + " " + conflictnode: mergenode}) + +for space in finallist: + print(str(finallist[space][0]) + " " + str(finallist[space][1]) + " {" + + space + "}") + +dwg = svgwrite.Drawing('dots.svg', profile='tiny') +dwg.add(svgwrite.image.Image(href="Karte_Deutschland.svg", size=(586, 793))) +for space in finallist: + ypoint = (793 - (((finallist[space][0] - SOUTHERNMOST) / YSPAN) * 793)) + xpoint = ((finallist[space][1] - WESTERNMOST) / XSPAN) * 586 + dwg.add(dwg.circle(center=(xpoint, ypoint), r=5, fill='green')) + dwg.add(dwg.text(space, insert=(xpoint + 5, ypoint), font_size=5)) + +dwg.save() + + +ledconf = open("conf.yml", "w") +i = 0 + +for space in finallist: + ledconf.write("#led" + str(i) + ":\n-\n") + for u in range(2, len(finallist[space])): + ledconf.write(" - " + finallist[space][u] + "\n") + i = i + 1 diff --git a/show_leds/show_leds.ino b/show_leds/show_leds.ino new file mode 100644 index 0000000..56eaa1f --- /dev/null +++ b/show_leds/show_leds.ino @@ -0,0 +1,79 @@ +#include +#include +#include +#include + + + +#define PIN 2 +#define NUMPIXELS 12 +const char* ssid = "CTDO-LEGACY"; +const char* password = "******"; +const char* apiEndpoint = "http://spacepanel.stablerock.de/leds"; +const int pollInterval = 10000; +HTTPClient http; + + +Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800); + +int delayval = 500; + +void setLED(int i, String value) { + String value_short = value.substring(1); + char charbuf[8]; + value_short.toCharArray(charbuf,8); + long int rgb = strtol(charbuf,0,16); //=>rgb=0x001234FE; + byte r=(byte)(rgb>>16); + byte g=(byte)(rgb>>8); + byte b=(byte)(rgb); + + Serial.print(value_short); + Serial.print("-> "); + Serial.print(r); + Serial.print(", "); + Serial.print(g); + Serial.print(", "); + Serial.println(b); + pixels.setPixelColor(i, pixels.Color(r/255,g/255,b/255)); + pixels.show(); +} + +void setup() { + Serial.begin(115200); + WiFi.begin(ssid, password); + Serial.println(WiFi.macAddress()); + while (WiFi.status() != WL_CONNECTED) { + delay(1000); + Serial.println("Connecting..."); + } + Serial.println("Connected."); + + pixels.begin(); +} + +void loop() { + Serial.println("Sending request..."); + http.begin(apiEndpoint); + int httpCode = http.GET(); + Serial.println("Success."); + if (httpCode == 200) { + String json = http.getString(); + const size_t capacity = JSON_ARRAY_SIZE(NUMPIXELS) + 510; + DynamicJsonDocument doc(capacity); + deserializeJson(doc, json); + for (int i = 0; i < NUMPIXELS; i++) { + Serial.print("LED" + String(i) + ": "); + const char* element = doc[i]; + String value = String(element); + setLED(i, value); + Serial.print("LED" ); + Serial.print(i); + Serial.print("Color: "); + Serial.println(value); + + } + } else { + Serial.println("Error: Statuscode" + httpCode); + } + delay(pollInterval); + } diff --git a/spacepanel_aggregator/go.mod b/spacepanel_aggregator/go.mod new file mode 100644 index 0000000..5d38084 --- /dev/null +++ b/spacepanel_aggregator/go.mod @@ -0,0 +1,9 @@ +module repos.ctdo.de/mamu/spacepanel_aggregator + +go 1.13 + +require ( + github.com/gin-gonic/gin v1.5.0 + github.com/valyala/fastjson v1.4.5 + gopkg.in/yaml.v2 v2.2.8 +) diff --git a/spacepanel_aggregator/go.sum b/spacepanel_aggregator/go.sum new file mode 100644 index 0000000..aced6c8 --- /dev/null +++ b/spacepanel_aggregator/go.sum @@ -0,0 +1,47 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.5.0 h1:fi+bqFAx/oLK54somfCtEZs9HeH1LHVoEPUgARpTqyc= +github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do= +github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc= +github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= +github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM= +github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= +github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8= +github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= +github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg= +github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/valyala/fastjson v1.4.5 h1:uSuLfXk2LzRtzwd3Fy5zGRBe0Vs7zhs11vjdko32xb4= +github.com/valyala/fastjson v1.4.5/go.mod h1:nV6MsjxL2IMJQUoHDIrjEI7oLyeqK6aBD7EFWPsvP8o= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= +gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= +gopkg.in/go-playground/validator.v9 v9.29.1 h1:SvGtYmN60a5CVKTOzMSyfzWDeZRxRuGvRQyEAKbw1xc= +gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/spacepanel_aggregator/httppoll.go b/spacepanel_aggregator/httppoll.go new file mode 100644 index 0000000..c5573bc --- /dev/null +++ b/spacepanel_aggregator/httppoll.go @@ -0,0 +1,76 @@ +package spacepanel_aggregator + +import ( + "crypto/tls" + "errors" + "fmt" + "io/ioutil" + "net/http" + "time" + + "github.com/valyala/fastjson" +) + +func PollWorker(url string, led int) { + for { + err := Worker(url) + if err != nil { + SetSpaceState(url, Unknown) + fmt.Println("LED", led, "URL:", url, err.Error()) + } + time.Sleep(sleeptime) + } +} + +var ( + insecureTransport = &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + + client = &http.Client{ + Transport: insecureTransport, + } +) + +func Worker(url string) error { + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return err + } + + resp, err := client.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return err + } + + value, err := fastjson.ParseBytes(data) + if err != nil { + return err + } + + if !value.Exists("state", "open") { + return errors.New("no space state existing") + } + + state := value.GetBool("state", "open") + + if state { + SetSpaceState(url, Open) + } else { + SetSpaceState(url, Close) + } + + return nil +} + +func SetSpaceState(url string, s State) { + lock.Lock() + spacestates[url] = s + lock.Unlock() +} diff --git a/spacepanel_aggregator/setup.go b/spacepanel_aggregator/setup.go new file mode 100644 index 0000000..867ffea --- /dev/null +++ b/spacepanel_aggregator/setup.go @@ -0,0 +1,86 @@ +package spacepanel_aggregator + +import ( + "fmt" + "github.com/gin-gonic/gin" + yaml "gopkg.in/yaml.v2" + io "io/ioutil" + "net/http" + "sync" + "time" +) + +var listen = ":8080" +var conffile = "conf.yml" +var sleeptime time.Duration = 60000000000 // nanoseconds +var leds [][]string +var spacestates map[string]State +var lock = sync.RWMutex{} + +func SetConf(s string) { + conffile = s +} + +func SetIf(s string) { + listen = s +} + +func Start() { + fmt.Println("Welcome to Spacepanel Aggregator!\n") + fmt.Println("Listen Interface: ", listen) + fmt.Println("Config-File: ", conffile) + bytes, err := io.ReadFile(conffile) + if err != nil { + ce(err) + } + err = yaml.Unmarshal(bytes, &leds) + + if err != nil { + ce(err) + panic("An error occured while parsing the conffile, quitting...") + } + spacestates = make(map[string]State) + for i := 0; i < len(leds); i++ { + for j := 0; j < len(leds[i]); j++ { + spacestates[leds[i][j]] = Unknown + go PollWorker(leds[i][j], i) + } + } + fmt.Println("Loaded", len(leds), "LED-configs and", len(spacestates), "spaces.") + + r := setupRouter() + _ = r.Run(listen) +} + +func getBestState(states []string) State { + returner := Unknown + for i := 0; i < len(states); i++ { + if spacestates[states[i]] < returner { + returner = spacestates[states[i]] + } + } + return returner +} + +func getLedStates(c *gin.Context) { + returner := make([]string, len(leds)) + for i := 0; i < len(leds); i++ { + returner[i] = colors[getBestState(leds[i])] + } + c.JSON(http.StatusOK, returner) +} + +func setupRouter() *gin.Engine { + gin.SetMode(gin.ReleaseMode) + r := gin.Default() + // Ping test + //r.GET("/leds", getLedStates()) + r.GET("/leds", getLedStates) + return r +} + +func ce(err error) { + if err != nil { + fmt.Println("ERROR: ", err.Error()) + } +} diff --git a/spacepanel_aggregator/spacepanel_aggregator/cmd.go b/spacepanel_aggregator/spacepanel_aggregator/cmd.go new file mode 100644 index 0000000..4386c0d --- /dev/null +++ b/spacepanel_aggregator/spacepanel_aggregator/cmd.go @@ -0,0 +1,44 @@ +package main + +import ( + "fmt" + "os" + sa "repos.ctdo.de/mamu/spacepanel_aggregator" +) + +const helptext string = "spacepanel_aggregator usage: \n\n -l IF:port default: *:8080 \n -f config-file default: conf.yml \n -h print help and exit\n" + +func main() { + conf := true + for i := 1; i < len(os.Args); i++ { + switch os.Args[i] { + case "-l": + i++ + if i < len(os.Args) { + sa.SetIf(os.Args[i]) + } else { + conf = false + } + case "-f": + i++ + if i < len(os.Args) { + sa.SetConf(os.Args[i]) + } else { + conf = false + } + default: + conf = false + i = len(os.Args) + } + + } + if conf { + sa.Start() + } else { + printHelp() + } +} + +func printHelp() { + fmt.Printf(helptext) +} diff --git a/spacepanel_aggregator/spacepanel_aggregator/conf.yml b/spacepanel_aggregator/spacepanel_aggregator/conf.yml new file mode 100644 index 0000000..c09bea5 --- /dev/null +++ b/spacepanel_aggregator/spacepanel_aggregator/conf.yml @@ -0,0 +1,184 @@ +#led0: +- + - https://www.devtal.de/api/ +#led1: +- + - https://www.binary-kitchen.de/spaceapi.php +#led2: +- + - https://status.aachen.ccc.de/spaceapi +#led3: +- + - https://schalter.ccchb.de/spaceapi.json +#led4: +- + - https://api.koeln.ccc.de +#led5: +- + - https://www.ccc-mannheim.de/spaceapi/spaceapi.json +#led6: +- + - http://cccfr.de/status/spaceapi.py +#led7: +- + - http://chaos-consulting.de/api/space.api +#led8: +- + - https://status.chaospott.de/status.json +#led9: +- + - https://chaoschemnitz.de/chch.json +#led10: +- + - https://www.ccc-p.org/spaceapi.json +#led11: +- + - http://doorstatus.c3re.de/status/json +#led12: +- + - http://status.ctdo.de/api/spaceapi/v13 +#led13: +- + - https://status.diyww.de/status.json +#led14: +- + - http://club.entropia.de/spaceapi +#led15: +- + - https://fablab.fau.de/spaceapi/ +#led16: +- + - https://spaceapi.futev.de/spaceapi.json +#led17: +- + - https://freieslabor.org/api/info +#led18: +- + - https://hackerspace-bielefeld.de/spacestatus/status.json +#led19: +- + - https://hacklabor.de/api/space/v1/ +#led20: +- + - http://spaceapi.hacksaar.de/status.json +#led21: +- + - https://status.hasi.it/spaceapi +#led22: +- + - https://status.kraut.space/api +#led23: +- + - http://status.leinelab.org/api/spaceapi.json +#led24: +- + - http://status.mainframe.io/api/spaceInfo +#led25: +- + - http://spaceapi.n39.eu/json +#led26: +- + - http://netzladen.org/api/status.json +#led27: +- + - https://api.nerd2nerd.org/status.json +#led28: +- + - https://cccgoe.de/spaceapi.php +#led29: +- + - http://api.openlab-augsburg.de/data.json +#led30: +- + - https://werkraum.freiraumzittau.de/spaceapi/13/ +#led31: +- + - https://spaceapi.reaktor23.org +#led32: +- + - http://status.stratum0.org/status.json +#led33: +- + - https://api.warpzone.ms/spaceapi +#led34: +- + - https://hsmr.cc/spaceapi.json +#led35: +- + - https://status.bckspc.de/spacestatus.php +#led36: +- + - http://stats.bytewerk.org/status.json +#led37: +- + - https://api.flipdot.org/ +#led38: +- + - https://spaceapi.hackzogtum-coburg.de +#led39: +- + - https://state.maglab.space/spaceapi.json +#led40: +- + - http://nobreakspace.org/status/spaceapi.json +#led41: +- + - https://bodensee.space/spaceapi/see-base.json +#led42: +- + - https://api.shackspace.de/v1/spaceapi +#led43: +- + - https://verschwoerhaus.de/feed/spaceapi +#led44: +- + - https://vspace.one/spaceapi.json +#led45: +- + - https://keinanschluss.un-hack-bar.de/spaceapi.json +#led46: +- + - https://www.hackerspace-sw.de/spaceapi.json +#led47: +- + - https://hamburg.ccc.de/dooris/status.json + - http://blog.attraktor.org/spaceapi/spaceapi.json +#led48: +- + - https://status.makerspace-erfurt.de/status.json + - http://status.bytespeicher.org/status.json +#led49: +- + - http://status.munichmakerlab.de/spaceapi.php + - http://api.muc.ccc.de/spaceapi.json +#led50: +- + - http://api.terminal21.de + - http://api.terminal21.de/status_ebk.json +#led51: +- + - https://fnord.istsystemrelevant.de/spaceapi.json + - https://chaosdorf.de/space_api.json +#led52: +- + - http://spaceapi.nordlab-ev.de + - https://api.chaostreff-flensburg.de/ +#led53: +- + - http://www.space-left.org/spaceapi13.json + - https://das-labor.org/status/api +#led54: +- + - http://www.turmlabor.de/spaces.api + - https://www.c3d2.de/spaceapi.json +#led55: +- + - http://spaceapi.k4cg.org/spaceapi.json + - http://api.fablab-nuernberg.de/spaceapi.php + - https://status.nerdberg.de/api/space +#led56: +- + - https://x-hain.de/spaceapi-0.13.json + - http://www.c-base.org/status.json + - https://spaceapi.motionlab.berlin/ + - https://spaceapi.afra-berlin.de/v1/status.json diff --git a/spacepanel_aggregator/types.go b/spacepanel_aggregator/types.go new file mode 100644 index 0000000..0a19d37 --- /dev/null +++ b/spacepanel_aggregator/types.go @@ -0,0 +1,239 @@ +package spacepanel_aggregator + +type State int + +const ( + Open = State(iota) + Close + Outdated + Unknown +) + +var colors = [4]string{"#00ff00", "#ff0000", "#0000ff", "#000000"} + +type V13 struct { + API string `json:"api"` + Cache struct { + Schedule string `json:"schedule"` + } `json:"cache"` + Cam []string `json:"cam"` + Contact struct { + Email string `json:"email"` + Facebook string `json:"facebook"` + Foursquare string `json:"foursquare"` + Google struct { + Plus string `json:"plus"` + } `json:"google"` + Identica string `json:"identica"` + Irc string `json:"irc"` + IssueMail string `json:"issue_mail"` + Jabber string `json:"jabber"` + Keymasters []struct { + Email string `json:"email"` + IrcNick string `json:"irc_nick"` + Name string `json:"name"` + Phone string `json:"phone"` + Twitter string `json:"twitter"` + } `json:"keymasters"` + Ml string `json:"ml"` + Phone string `json:"phone"` + Sip string `json:"sip"` + Twitter string `json:"twitter"` + } `json:"contact"` + Events []struct { + Extra string `json:"extra"` + Name string `json:"name"` + Timestamp float64 `json:"timestamp"` + Type string `json:"type"` + } `json:"events"` + Feeds struct { + Blog struct { + Type string `json:"type"` + URL string `json:"url"` + } `json:"blog"` + Calendar struct { + Type string `json:"type"` + URL string `json:"url"` + } `json:"calendar"` + Flickr struct { + Type string `json:"type"` + URL string `json:"url"` + } `json:"flickr"` + Wiki struct { + Type string `json:"type"` + URL string `json:"url"` + } `json:"wiki"` + } `json:"feeds"` + IssueReportChannels []string `json:"issue_report_channels"` + Location struct { + Address string `json:"address"` + Lat float64 `json:"lat"` + Lon float64 `json:"lon"` + } `json:"location"` + Logo string `json:"logo"` + Projects []string `json:"projects"` + RadioShow []struct { + End string `json:"end"` + Name string `json:"name"` + Start string `json:"start"` + Type string `json:"type"` + URL string `json:"url"` + } `json:"radio_show"` + Sensors struct { + AccountBalance []struct { + Description string `json:"description"` + Location string `json:"location"` + Name string `json:"name"` + Unit string `json:"unit"` + Value float64 `json:"value"` + } `json:"account_balance"` + Barometer []struct { + Description string `json:"description"` + Location string `json:"location"` + Name string `json:"name"` + Unit string `json:"unit"` + Value float64 `json:"value"` + } `json:"barometer"` + BeverageSupply []struct { + Description string `json:"description"` + Location string `json:"location"` + Name string `json:"name"` + Unit string `json:"unit"` + Value float64 `json:"value"` + } `json:"beverage_supply"` + DoorLocked []struct { + Description string `json:"description"` + Location string `json:"location"` + Name string `json:"name"` + Value bool `json:"value"` + } `json:"door_locked"` + Humidity []struct { + Description string `json:"description"` + Location string `json:"location"` + Name string `json:"name"` + Unit string `json:"unit"` + Value float64 `json:"value"` + } `json:"humidity"` + NetworkConnections []struct { + Description string `json:"description"` + Location string `json:"location"` + Machines []struct { + Mac string `json:"mac"` + Name string `json:"name"` + } `json:"machines"` + Name string `json:"name"` + Type string `json:"type"` + Value float64 `json:"value"` + } `json:"network_connections"` + PeopleNowPresent []struct { + Description string `json:"description"` + Location string `json:"location"` + Name string `json:"name"` + Names []string `json:"names"` + Value float64 `json:"value"` + } `json:"people_now_present"` + PowerConsumption []struct { + Description string `json:"description"` + Location string `json:"location"` + Name string `json:"name"` + Unit string `json:"unit"` + Value float64 `json:"value"` + } `json:"power_consumption"` + Radiation struct { + Alpha []struct { + ConversionFactor float64 `json:"conversion_factor"` + DeadTime float64 `json:"dead_time"` + Description string `json:"description"` + Location string `json:"location"` + Name string `json:"name"` + Unit string `json:"unit"` + Value float64 `json:"value"` + } `json:"alpha"` + Beta []struct { + ConversionFactor float64 `json:"conversion_factor"` + DeadTime float64 `json:"dead_time"` + Description string `json:"description"` + Location string `json:"location"` + Name string `json:"name"` + Unit string `json:"unit"` + Value float64 `json:"value"` + } `json:"beta"` + BetaGamma []struct { + ConversionFactor float64 `json:"conversion_factor"` + DeadTime float64 `json:"dead_time"` + Description string `json:"description"` + Location string `json:"location"` + Name string `json:"name"` + Unit string `json:"unit"` + Value float64 `json:"value"` + } `json:"beta_gamma"` + Gamma []struct { + ConversionFactor float64 `json:"conversion_factor"` + DeadTime float64 `json:"dead_time"` + Description string `json:"description"` + Location string `json:"location"` + Name string `json:"name"` + Unit string `json:"unit"` + Value float64 `json:"value"` + } `json:"gamma"` + } `json:"radiation"` + Temperature []struct { + Description string `json:"description"` + Location string `json:"location"` + Name string `json:"name"` + Unit string `json:"unit"` + Value float64 `json:"value"` + } `json:"temperature"` + TotalMemberCount []struct { + Description string `json:"description"` + Location string `json:"location"` + Name string `json:"name"` + Value float64 `json:"value"` + } `json:"total_member_count"` + Wind []struct { + Description string `json:"description"` + Location string `json:"location"` + Name string `json:"name"` + Properties struct { + Direction struct { + Unit string `json:"unit"` + Value float64 `json:"value"` + } `json:"direction"` + Elevation struct { + Unit string `json:"unit"` + Value float64 `json:"value"` + } `json:"elevation"` + Gust struct { + Unit string `json:"unit"` + Value float64 `json:"value"` + } `json:"gust"` + Speed struct { + Unit string `json:"unit"` + Value float64 `json:"value"` + } `json:"speed"` + } `json:"properties"` + } `json:"wind"` + } `json:"sensors"` + Space string `json:"space"` + Spacefed struct { + Spacenet bool `json:"spacenet"` + Spacephone bool `json:"spacephone"` + Spacesaml bool `json:"spacesaml"` + } `json:"spacefed"` + State struct { + Icon struct { + Closed string `json:"closed"` + Open string `json:"open"` + } `json:"icon"` + Lastchange float64 `json:"lastchange"` + Message string `json:"message"` + Open interface{} `json:"open"` + TriggerPerson string `json:"trigger_person"` + } `json:"state"` + Stream struct { + M4 string `json:"m4"` + Mjpeg string `json:"mjpeg"` + Ustream string `json:"ustream"` + } `json:"stream"` + URL string `json:"url"` +} \ No newline at end of file