func journalTailer() { cmd := exec.Command("journalctl", "--user-unit=gohome@*", "-f", "-n0", "-q", "--output=json") stdout, err := cmd.StdoutPipe() if err != nil { log.Fatal(err) } if err := cmd.Start(); err != nil { log.Fatal(err) } scanner := bufio.NewScanner(stdout) for scanner.Scan() { var data map[string]interface{} err := json.Unmarshal([]byte(scanner.Text()), &data) if err != nil { log.Println("Error decoding json:", err) continue } if message, ok := data["MESSAGE"].(string); ok { var source string if user_unit, ok := data["_SYSTEMD_USER_UNIT"].(string); ok { source = stripUnitName(user_unit) } else { source = "systemd" } fields := map[string]interface{}{ "message": message, "source": source, } ev := pubsub.NewEvent("log", fields) services.Publisher.Emit(ev) } } }
func sendAnswer(request *pubsub.Event, source string, answer Answer) { fields := pubsub.Fields{ "source": source, "target": request.StringField("source"), } if answer.Text != "" { fields["message"] = answer.Text } if answer.Json != nil { fields["json"] = answer.Json } remote := request.StringField("remote") if remote != "" { fields["remote"] = remote } topic := "alert" reply_to := request.StringField("reply_to") if reply_to != "" { topic = reply_to } response := pubsub.NewEvent(topic, fields) Publisher.Emit(response) }
func ExampleLookupDeviceNameMissing() { config, _ := OpenRaw([]byte(yml)) fields := pubsub.Fields{"source": "a02"} ev := pubsub.NewEvent("x10", fields) fmt.Println(config.LookupDeviceName(ev)) // Output: // x10.a02 }
func (self *Thermostat) Heartbeat(now time.Time) { self.Check(now) // emit event for datalogging ev := pubsub.NewEvent("heating", pubsub.Fields{"source": "ch", "heating": self.State}) self.Publisher.Emit(ev) // repeat current state self.Command() //log.Println(self.ShortStatus(now)) }
func emit(code string) { log.Println("Publishing:", code) fields := map[string]interface{}{ "origin": "rfid", "command": "tag", "source": code, } event := pubsub.NewEvent("rfid", fields) services.Publisher.Emit(event) }
func SendQuery(query, source, remote, reply_to string) { fields := pubsub.Fields{ "source": source, "query": query, "remote": remote, "reply_to": reply_to, } ev := pubsub.NewEvent("query", fields) Publisher.Emit(ev) }
func (self EventAction) Video(device string, preset int64, secs float64, ir bool) { log.Printf("Video: %s at %d for %.1fs (ir: %v)", device, preset, secs, ir) fields := pubsub.Fields{ "device": device, "command": "video", "timeout": secs, "preset": preset, "ir": ir, } ev := pubsub.NewEvent("command", fields) services.Publisher.Emit(ev) }
func SendAlert(message string, target string, subtopic string, interval int64) { fields := pubsub.Fields{ "message": message, "target": target, } if subtopic != "" { fields["subtopic"] = subtopic fields["interval"] = interval } ev := pubsub.NewEvent("alert", fields) Publisher.Emit(ev) }
// Run the service func (self *Service) Run() error { loc := Location{ Latitude: services.Config.Earth.Latitude, Longitude: services.Config.Earth.Longitude, } for tev := range eventChannel(loc) { ev := pubsub.NewEvent("earth", pubsub.Fields{"command": tev.Event, "source": "home"}) services.Publisher.Emit(ev) } return nil }
func (self *Service) queryTag(q services.Question) string { tagName := strings.ToLower(q.Args) if _, ok := services.Config.Devices["rfid."+tagName]; !ok { return fmt.Sprintf("Tag %s not found", tagName) } fields := map[string]interface{}{ "source": tagName, "command": "tag", } ev := pubsub.NewEvent("person", fields) services.Publisher.Emit(ev) return fmt.Sprintf("Emitted tag for %s", tagName) }
func (self EventAction) StartTimer(name string, d int64) { // log.Printf("Starting timer: %s for %ds", name, d) duration := time.Duration(d) * time.Second if timer, ok := self.service.timers[name]; ok { // cancel any existing timer.Stop() } timer := time.AfterFunc(duration, func() { // emit timer event fields := map[string]interface{}{ "source": name, "command": "on", } ev := pubsub.NewEvent("timer", fields) services.Publisher.Emit(ev) }) self.service.timers[name] = timer }
func Heartbeat(id string) { started := time.Now() fields := pubsub.Fields{ "pid": os.Getpid(), "started": started.Format(time.RFC3339), "source": id, } // wait 5 seconds before heartbeating - if the process dies very soon time.Sleep(time.Second * 5) for { uptime := int(time.Now().Sub(started).Seconds()) fields["uptime"] = uptime ev := pubsub.NewEvent("heartbeat", fields) Publisher.Emit(ev) time.Sleep(time.Second * 60) } }
func ExampleQuerySubscriber() { fields := pubsub.Fields{"query": "help"} query := pubsub.NewEvent("query", fields) li := dummy.Subscriber{ Events: []*pubsub.Event{query}, } Subscriber = &li em := dummy.Publisher{} Publisher = &em mock := MockService{ queryHandlers: map[string]QueryHandler{"help": StaticHandler("squiggle")}, } enabled = []Service{&mock} QuerySubscriber() fmt.Println(len(em.Events)) fmt.Println(em.Events[0].StringField("message")) // Output: // 1 // squiggle }
func apiConfig(w http.ResponseWriter, r *http.Request) { q := r.URL.Query() path := q.Get("path") if path == "" { err := errors.New("path parameter required") errorResponse(w, err) return } // retrieve key from store value, err := services.Stor.Get(q.Get("path")) if err != nil { errorResponse(w, err) return } if r.Method == "GET" { w.Header().Add("Content-Type", "application/yaml; charset=utf-8") w.Write([]byte(value)) } else if r.Method == "POST" { data, err := ioutil.ReadAll(r.Body) if err != nil { errorResponse(w, err) return } sout := string(data) if sout != value { // set store services.Stor.Set(path, sout) // emit event fields := pubsub.Fields{ "path": path, } ev := pubsub.NewEvent("config", fields) services.Publisher.Emit(ev) log.Printf("%s changed, emitted config event", path) } } }
// Run the service func (service *Service) Run() error { addr, err := net.ResolveUDPAddr("udp", ":3865") if err != nil { return err } sock, err := net.ListenUDP("udp", addr) if err != nil { return err } var buf [1024]byte for { rlen, _, err := sock.ReadFromUDP(buf[0:]) if err != nil { log.Fatal(err) continue } data := string(buf[:rlen]) //log.Println("Received:", data) source, power := Process(data) if source != "" && power != "" { var command string switch power { case "1": command = "on" case "0": command = "off" } fields := map[string]interface{}{ "origin": "xpl", "command": command, "source": source, } event := pubsub.NewEvent("xpl", fields) services.Publisher.Emit(event) } } }
func translatePacket(packet gorfxtrx.Packet) *pubsub.Event { var ev *pubsub.Event switch p := packet.(type) { case *gorfxtrx.Status: // no event emitted protocols := strings.Join(p.Protocols(), ", ") log.Printf("Status: type: %s transceiver: %d firmware: %d protocols: %s", p.TypeString(), p.TransceiverType, p.FirmwareVersion, protocols) case *gorfxtrx.LightingX10: fields := map[string]interface{}{ "origin": Origin, "source": p.Id(), "group": p.Id()[:1], "command": p.Command(), } ev = pubsub.NewEvent("x10", fields) case *gorfxtrx.LightingHE: id := fmt.Sprintf("%07X%1X", p.HouseCode, p.UnitCode) fields := map[string]interface{}{ "origin": Origin, "source": id, "command": p.Command(), } ev = pubsub.NewEvent("homeeasy", fields) case *gorfxtrx.Temp: source := fmt.Sprintf("thn132n.%s", p.Id()[0:2]) fields := map[string]interface{}{ "origin": Origin, "source": source, "temp": p.Temp, "battery": p.Battery, } ev = pubsub.NewEvent("temp", fields) case *gorfxtrx.TempHumid: major := strings.ToLower(strings.Split(p.Type(), ",")[0]) source := fmt.Sprintf("%s.%s", major, p.Id()[0:2]) fields := map[string]interface{}{ "origin": Origin, "source": source, "temp": p.Temp, "humidity": p.Humidity, "battery": p.Battery, } ev = pubsub.NewEvent("temp", fields) case *gorfxtrx.Wind: source := strings.ToLower(p.Type()) fields := map[string]interface{}{ "origin": Origin, "source": source, "speed": p.Gust, "avgspeed": p.AverageSpeed, "dir": p.Direction, "battery": p.Battery, } ev = pubsub.NewEvent("wind", fields) case *gorfxtrx.Rain: device := strings.ToLower(p.Type()) source := fmt.Sprintf("%s.%s", device, p.Id()) fields := map[string]interface{}{ "origin": Origin, "source": source, "rate": p.RainRate, "all_total": p.RainTotal, "battery": p.Battery, } ev = pubsub.NewEvent("rain", fields) case *gorfxtrx.Chime: device := deviceName(p.Type()) source := fmt.Sprintf("%s.%s", device, strings.Replace(p.Id(), ":", "", 1)) fields := map[string]interface{}{ "origin": Origin, "source": source, "chime": p.Chime, "battery": p.Battery, "command": "on", } ev = pubsub.NewEvent("chime", fields) default: log.Printf("Ignored unhandled packet: %#v\n", packet) } return ev }
// Run the service func (self *Service) Run() error { self.log = openLogFile() self.timers = map[string]*time.Timer{} self.configUpdated = make(chan bool, 2) // load templated automata var err error self.automata, err = loadAutomata() if err != nil { return err } // persistance can take a while and delay the workflow, so run in background chanPersist := make(chan string, 32) go func() { for automaton := range chanPersist { self.PersistStore(self.automata, automaton) } }() self.RestoreStore(self.automata) log.Printf("Initial states: %s", self.automata) ch := services.Subscriber.Channel() defer services.Subscriber.Close(ch) for { select { case ev := <-ch: if ev.Topic == "alert" || ev.Topic == "heating" || strings.HasPrefix(ev.Topic, "_") { continue } if ev.Command() == "" && ev.State() == "" { continue } // send relevant events to the automata event := EventWrapper{ev} self.automata.Process(event) case change := <-self.automata.Changes: trigger := change.Trigger.(EventWrapper) s := fmt.Sprintf("%-17s %s->%s", "["+change.Automaton+"]", change.Old, change.New) log.Printf("%-40s (event: %s)", s, trigger) chanPersist <- change.Automaton // emit event fields := pubsub.Fields{ "device": change.Automaton, "state": change.New, "trigger": trigger.String(), } ev := pubsub.NewEvent("state", fields) services.Publisher.Emit(ev) case action := <-self.automata.Actions: wrapper := action.Trigger.(EventWrapper) ea := EventAction{self, wrapper.event, action.Change} err := DynamicCall(ea, action.Name) if err != nil { log.Println("Error:", err) } case <-self.configUpdated: // live reload the automata! log.Println("Automata config updated, reloading") updated, err := loadAutomata() if err != nil { log.Println("Failed to reload automata:", err) continue } self.RestoreStore(updated) self.automata = updated log.Println("Automata reloaded successfully") } } return nil }