diff --git a/README.md b/README.md index becbcc2..9d1be8e 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,10 @@ Supported types are: - `partition-with-violated-zones` - `zone-isolate` +### Filtering events by index (I guess "zone", but I'm not sure) + +Use the `--allowed-indexes=1,2,3,...` command line parameter to set the list of allowed indexes (of course provide your own list instead of `1,2,3,...`). If that parameter is not provided, then all indexes are allowed; otherwise the notification is sent for all indexes. + ## Debugging Set the `OMIT_TG` environment variable to, well, omit sending anything over to Telegram and just see the logs instead. diff --git a/filters.go b/filters.go index c5c749e..b59daf0 100644 --- a/filters.go +++ b/filters.go @@ -38,6 +38,34 @@ func FilterByType(ev <-chan satel.Event, allowedTypes []satel.ChangeType) <-chan return returnChan } +func FilterByIndex(ev <-chan satel.Event, allowedIndexes []int) <-chan satel.Event { + returnChan := make(chan satel.Event) + + if len(allowedIndexes) == 0 { + // no allowed indexes == all indexes are allowed + go func() { + for e := range ev { + returnChan <- e + } + close(returnChan) + }() + } else { + go func() { + for e := range ev { + for _, allowedIndex := range allowedIndexes { + if allowedIndex == e.Index { + returnChan <- e + continue + } + } + } + close(returnChan) + }() + } + + return returnChan +} + type EventKey struct { ChangeType satel.ChangeType Index int diff --git a/filters_test.go b/filters_test.go index 21fb4fc..39b3fa8 100644 --- a/filters_test.go +++ b/filters_test.go @@ -65,6 +65,61 @@ func TestSatelEventTypeFiltering_NoAllowedEventTypesMeansAllAreAllowed(t *testin } } +func TestSatelIndexFiltering(t *testing.T) { + testEvents := make(chan satel.Event) + receivedEvents := make([]satel.Event, 0) + wg := sync.WaitGroup{} + + go func() { + wg.Add(1) + for e := range FilterByIndex(testEvents, []int{1, 3}) { + receivedEvents = append(receivedEvents, e) + } + wg.Done() + }() + + testEvents <- satel.Event{Type: satel.ArmedPartition, Index: 1, Value: true} + testEvents <- satel.Event{Type: satel.DoorOpened, Index: 2, Value: true} + testEvents <- satel.Event{Type: satel.PartitionAlarm, Index: 3, Value: true} + testEvents <- satel.Event{Type: satel.PartitionFireAlarm, Index: 4, Value: true} + testEvents <- satel.Event{Type: satel.TroublePart1, Index: 5, Value: true} + testEvents <- satel.Event{Type: satel.ZoneTamper, Index: 6, Value: true} + + close(testEvents) + wg.Wait() + + assert.Len(t, receivedEvents, 2) + assert.Contains(t, receivedEvents, satel.Event{Type: satel.ArmedPartition, Index: 1, Value: true}) + assert.Contains(t, receivedEvents, satel.Event{Type: satel.PartitionAlarm, Index: 3, Value: true}) +} + +func TestSatelIndexFiltering_NoAllowedEventTypesMeansAllAreAllowed(t *testing.T) { + testEvents := make(chan satel.Event) + receivedEvents := make([]satel.Event, 0) + wg := sync.WaitGroup{} + myReasonableMaxIndex := 100 // I wanted to use math.MaxInt at first, but it's kind of a waste of time here + + go func() { + wg.Add(1) + for e := range FilterByIndex(testEvents, []int{}) { + receivedEvents = append(receivedEvents, e) + } + wg.Done() + }() + + for i := 0; i < myReasonableMaxIndex; i++ { + testEvents <- satel.Event{Type: satel.ArmedPartition, Index: i, Value: true} + } + + close(testEvents) + wg.Wait() + + assert.Len(t, receivedEvents, myReasonableMaxIndex) + for i := 0; i < myReasonableMaxIndex; i++ { + assert.Contains(t, receivedEvents, satel.Event{Type: satel.ArmedPartition, Index: i, Value: true}) + } +} + func TestSatelLastSeenFiltering(t *testing.T) { f, err := os.CreateTemp("", "TestSatelLastSeenFiltering") assert.NoError(t, err) diff --git a/main.go b/main.go index 95ebcbf..b53b34c 100644 --- a/main.go +++ b/main.go @@ -68,11 +68,12 @@ func (self RealSleeper) Sleep(ch chan<- interface{}) { }() } -func getCmdLineParams(logger *log.Logger) (string, []int64, []satel.ChangeType) { +func getCmdLineParams(logger *log.Logger) (string, []int64, []satel.ChangeType, []int) { satelApiAddr := flag.String("satel-addr", "", "Address that should be used to connect to the SATEL device") satelApiPort := flag.String("satel-port", "7094", "Port that should be used to connect to the SATEL device") chatIdRaw := flag.String("tg-chat-id", "", "Telegram Chat ID where to send updates. Use \",\" to specify multiple IDs.") allowedTypesRaw := flag.String("allowed-types", "", "Satel change types that are allowed. All other types will be discarded. By default all are allowed. Use \",\" to specify multiple types.") + allowedIndexesRaw := flag.String("allowed-indexes", "", "Satel indexes (zones?) that are allowed. All other indexes will be discarded. By default all are allowed. Use \",\" to specify multiple indexes.") flag.Parse() if len(*satelApiAddr) == 0 || len(*satelApiPort) == 0 || len(*chatIdRaw) == 0 { @@ -96,9 +97,18 @@ func getCmdLineParams(logger *log.Logger) (string, []int64, []satel.ChangeType) } allowedTypes = append(allowedTypes, allowedType) } + allowedIndexesStrings := strings.Split(*allowedIndexesRaw, ",") + var allowedIndexes []int + for _, allowedIndexStr := range allowedIndexesStrings { + allowedIndex, err := strconv.ParseInt(allowedIndexStr, 10, 0) + if err != nil { + logger.Fatalf("Tried to use a non-int value for one of allowed indexes: %s. That's bad.", allowedIndexStr) + } + allowedIndexes = append(allowedIndexes, int(allowedIndex)) + } satelAddr := fmt.Sprintf("%s:%s", *satelApiAddr, *satelApiPort) - return satelAddr, chatIds, allowedTypes + return satelAddr, chatIds, allowedTypes, allowedIndexes } func makeSatel(satelAddr string) *satel.Satel { @@ -117,7 +127,7 @@ func main() { logger = log.New(os.Stderr, "Main", log.Lmicroseconds) ) - satelAddr, chatIds, allowedTypes := getCmdLineParams(logger) + satelAddr, chatIds, allowedTypes, allowedIndexes := getCmdLineParams(logger) s := makeSatel(satelAddr) logger.Printf("Connected to Satel: %s", satelAddr) @@ -135,9 +145,10 @@ func main() { tgSenderWorker(tgEvents, &wg, sleeper, log.New(os.Stderr, "TgSender", log.Lmicroseconds)), tgSender, &wg, log.New(os.Stderr, "SendToTg", log.Lmicroseconds))) - for e := range FilterByType( + for e := range FilterByIndex(FilterByType( FilterByLastSeen(s.Events, "hs_wro_last_seen.bin", log.New(os.Stderr, "FilterByLastSeen", log.Lmicroseconds)), - allowedTypes) { + allowedTypes), + allowedIndexes) { logger.Print("Received change from SATEL: ", e) for _, chatId := range chatIds { sendTgMessage(tgEvents, SatelMsgContent{e}, chatId)