1
0
Fork 0

Possibility to filter by ChangeType

This commit is contained in:
Michał Rudowicz 2024-02-18 18:44:08 +01:00
parent 079e32e893
commit ab5bd412f2
6 changed files with 228 additions and 13 deletions

View File

@ -13,6 +13,51 @@ I didn't even test it yet so no idea if it works
$ TELEGRAM_APITOKEN=YOUR_API_TOKEN ./alarm_bot --satel_addr=127.0.0.1 --satel_port=31337 --tg_chat_id=YOUR_CHAT_ID_FROM_BOTFATHER $ TELEGRAM_APITOKEN=YOUR_API_TOKEN ./alarm_bot --satel_addr=127.0.0.1 --satel_port=31337 --tg_chat_id=YOUR_CHAT_ID_FROM_BOTFATHER
``` ```
### Filtering events by change type
It's possible to filter events by change type. Use the `--allowed-types=TYPE1,TYPE2,...` command line parameter to do that. If that parameter is not provided, then all change types are allowed, otherwise only the provided ones will be used for notifications.
Supported types are:
- `zone-violation`
- `zone-tamper`
- `zone-alarm`
- `zone-tamper-alarm`
- `zone-alarm-memory`
- `zone-tamper-alarm-memory`
- `zone-bypass`
- `zone-no-violation-trouble`
- `zone-long-violation-trouble`
- `armed-partition-suppressed`
- `armed-partition`
- `partition-armed-mode-2`
- `partition-armed-mode-3`
- `partition-with-1st-code-enter`
- `partition-entry-time`
- `partition-exit-time-over-10s`
- `partition-exit-time-under-10s`
- `partition-temporary-blocked`
- `partition-blocked-guard-round`
- `partition-alarm`
- `partition-fire-alarm`
- `partition-alarm-memory`
- `partition-fire-alarm-memory`
- `output`
- `doors-opened`
- `doors-opened-long`
- `status-bit`
- `trouble-part-1`
- `trouble-part-2`
- `trouble-part-3`
- `trouble-part-4`
- `trouble-part-5`
- `trouble-memory-part-1`
- `trouble-memory-part-2`
- `trouble-memory-part-3`
- `trouble-memory-part-4`
- `trouble-memory-part-5`
- `partition-with-violated-zones`
- `zone-isolate`
## Debugging ## Debugging
Set the `OMIT_TG` environment variable to, well, omit sending anything over to Telegram and just see the logs instead. Set the `OMIT_TG` environment variable to, well, omit sending anything over to Telegram and just see the logs instead.

View File

@ -13,6 +13,15 @@ import (
func FilterByType(ev <-chan satel.Event, allowedTypes []satel.ChangeType) <-chan satel.Event { func FilterByType(ev <-chan satel.Event, allowedTypes []satel.ChangeType) <-chan satel.Event {
returnChan := make(chan satel.Event) returnChan := make(chan satel.Event)
if len(allowedTypes) == 0 {
// no allowed types == all types are allowed
go func() {
for e := range ev {
returnChan <- e
}
close(returnChan)
}()
} else {
go func() { go func() {
for e := range ev { for e := range ev {
for _, allowedType := range allowedTypes { for _, allowedType := range allowedTypes {
@ -24,6 +33,7 @@ func FilterByType(ev <-chan satel.Event, allowedTypes []satel.ChangeType) <-chan
} }
close(returnChan) close(returnChan)
}() }()
}
return returnChan return returnChan
} }

View File

@ -39,6 +39,32 @@ func TestSatelEventTypeFiltering(t *testing.T) {
assert.Contains(t, receivedEvents, satel.Event{Type: satel.PartitionFireAlarm, Index: 4, Value: true}) assert.Contains(t, receivedEvents, satel.Event{Type: satel.PartitionFireAlarm, Index: 4, Value: true})
} }
func TestSatelEventTypeFiltering_NoAllowedEventTypesMeansAllAreAllowed(t *testing.T) {
testEvents := make(chan satel.Event)
receivedEvents := make([]satel.Event, 0)
wg := sync.WaitGroup{}
go func() {
wg.Add(1)
for e := range FilterByType(testEvents, []satel.ChangeType{}) {
receivedEvents = append(receivedEvents, e)
}
wg.Done()
}()
for index, ct := range SUPPORTED_CHANGE_TYPES {
testEvents <- satel.Event{Type: ct, Index: index, Value: true}
}
close(testEvents)
wg.Wait()
assert.Len(t, receivedEvents, len(SUPPORTED_CHANGE_TYPES))
for index, ct := range SUPPORTED_CHANGE_TYPES {
assert.Contains(t, receivedEvents, satel.Event{Type: ct, Index: index, Value: true})
}
}
func TestSatelLastSeenFiltering(t *testing.T) { func TestSatelLastSeenFiltering(t *testing.T) {
f, err := os.CreateTemp("", "TestSatelLastSeenFiltering") f, err := os.CreateTemp("", "TestSatelLastSeenFiltering")
assert.NoError(t, err) assert.NoError(t, err)

20
main.go
View File

@ -68,10 +68,11 @@ func (self RealSleeper) Sleep(ch chan<- interface{}) {
}() }()
} }
func getCmdLineParams(logger *log.Logger) (string, []int64) { func getCmdLineParams(logger *log.Logger) (string, []int64, []satel.ChangeType) {
satelApiAddr := flag.String("satel-addr", "", "Address that should be used to connect to the SATEL device") 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") 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.") 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.")
flag.Parse() flag.Parse()
if len(*satelApiAddr) == 0 || len(*satelApiPort) == 0 || len(*chatIdRaw) == 0 { if len(*satelApiAddr) == 0 || len(*satelApiPort) == 0 || len(*chatIdRaw) == 0 {
@ -86,9 +87,18 @@ func getCmdLineParams(logger *log.Logger) (string, []int64) {
} }
chatIds = append(chatIds, chatId) chatIds = append(chatIds, chatId)
} }
allowedTypesStrings := strings.Split(*allowedTypesRaw, ",")
var allowedTypes []satel.ChangeType
for _, allowedTypeStr := range allowedTypesStrings {
allowedType, err := StringToSatelChangeType(allowedTypeStr)
if err != nil {
logger.Fatalf("Error trying to understand an allowed type: %s.", err)
}
allowedTypes = append(allowedTypes, allowedType)
}
satelAddr := fmt.Sprintf("%s:%s", *satelApiAddr, *satelApiPort) satelAddr := fmt.Sprintf("%s:%s", *satelApiAddr, *satelApiPort)
return satelAddr, chatIds return satelAddr, chatIds, allowedTypes
} }
func makeSatel(satelAddr string) *satel.Satel { func makeSatel(satelAddr string) *satel.Satel {
@ -107,7 +117,7 @@ func main() {
logger = log.New(os.Stderr, "Main", log.Lmicroseconds) logger = log.New(os.Stderr, "Main", log.Lmicroseconds)
) )
satelAddr, chatIds := getCmdLineParams(logger) satelAddr, chatIds, allowedTypes := getCmdLineParams(logger)
s := makeSatel(satelAddr) s := makeSatel(satelAddr)
logger.Printf("Connected to Satel: %s", satelAddr) logger.Printf("Connected to Satel: %s", satelAddr)
@ -125,7 +135,9 @@ func main() {
tgSenderWorker(tgEvents, &wg, sleeper, log.New(os.Stderr, "TgSender", log.Lmicroseconds)), tgSenderWorker(tgEvents, &wg, sleeper, log.New(os.Stderr, "TgSender", log.Lmicroseconds)),
tgSender, &wg, log.New(os.Stderr, "SendToTg", log.Lmicroseconds))) tgSender, &wg, log.New(os.Stderr, "SendToTg", log.Lmicroseconds)))
for e := range FilterByLastSeen(s.Events, "hs_wro_last_seen.bin", log.New(os.Stderr, "FilterByLastSeen", log.Lmicroseconds)) { for e := range FilterByType(
FilterByLastSeen(s.Events, "hs_wro_last_seen.bin", log.New(os.Stderr, "FilterByLastSeen", log.Lmicroseconds)),
allowedTypes) {
logger.Print("Received change from SATEL: ", e) logger.Print("Received change from SATEL: ", e)
for _, chatId := range chatIds { for _, chatId := range chatIds {
sendTgMessage(tgEvents, SatelMsgContent{e}, chatId) sendTgMessage(tgEvents, SatelMsgContent{e}, chatId)

100
satel_utils.go Normal file
View File

@ -0,0 +1,100 @@
package main
import (
"errors"
"fmt"
"github.com/probakowski/go-satel"
)
var SUPPORTED_CHANGE_TYPES = [...]satel.ChangeType{
satel.ZoneViolation,
satel.ZoneTamper,
satel.ZoneAlarm,
satel.ZoneTamperAlarm,
satel.ZoneAlarmMemory,
satel.ZoneTamperAlarmMemory,
satel.ZoneBypass,
satel.ZoneNoViolationTrouble,
satel.ZoneLongViolationTrouble,
satel.ArmedPartitionSuppressed,
satel.ArmedPartition,
satel.PartitionArmedInMode2,
satel.PartitionArmedInMode3,
satel.PartitionWith1stCodeEntered,
satel.PartitionEntryTime,
satel.PartitionExitTimeOver10s,
satel.PartitionExitTimeUnder10s,
satel.PartitionTemporaryBlocked,
satel.PartitionBlockedForGuardRound,
satel.PartitionAlarm,
satel.PartitionFireAlarm,
satel.PartitionAlarmMemory,
satel.PartitionFireAlarmMemory,
satel.Output,
satel.DoorOpened,
satel.DoorOpenedLong,
satel.StatusBit,
satel.TroublePart1,
satel.TroublePart2,
satel.TroublePart3,
satel.TroublePart4,
satel.TroublePart5,
satel.TroubleMemoryPart1,
satel.TroubleMemoryPart2,
satel.TroubleMemoryPart3,
satel.TroubleMemoryPart4,
satel.TroubleMemoryPart5,
satel.PartitionWithViolatedZones,
satel.ZoneIsolate,
}
var SATEL_STRING_TO_CHANGE_TYPE = map[string]satel.ChangeType{
"zone-violation": satel.ZoneViolation,
"zone-tamper": satel.ZoneTamper,
"zone-alarm": satel.ZoneAlarm,
"zone-tamper-alarm": satel.ZoneTamperAlarm,
"zone-alarm-memory": satel.ZoneAlarmMemory,
"zone-tamper-alarm-memory": satel.ZoneTamperAlarmMemory,
"zone-bypass": satel.ZoneBypass,
"zone-no-violation-trouble": satel.ZoneNoViolationTrouble,
"zone-long-violation-trouble": satel.ZoneLongViolationTrouble,
"armed-partition-suppressed": satel.ArmedPartitionSuppressed,
"armed-partition": satel.ArmedPartition,
"partition-armed-mode-2": satel.PartitionArmedInMode2,
"partition-armed-mode-3": satel.PartitionArmedInMode3,
"partition-with-1st-code-entered": satel.PartitionWith1stCodeEntered,
"partition-entry-time": satel.PartitionEntryTime,
"partition-exit-time-over-10s": satel.PartitionExitTimeOver10s,
"partition-exit-time-under-10s": satel.PartitionExitTimeUnder10s,
"partition-temporary-blocked": satel.PartitionTemporaryBlocked,
"partition-blocked-guard-round": satel.PartitionBlockedForGuardRound,
"partition-alarm": satel.PartitionAlarm,
"partition-fire-alarm": satel.PartitionFireAlarm,
"partition-alarm-memory": satel.PartitionAlarmMemory,
"partition-fire-alarm-memory": satel.PartitionFireAlarmMemory,
"output": satel.Output,
"doors-opened": satel.DoorOpened,
"doors-opened-long": satel.DoorOpenedLong,
"status-bit": satel.StatusBit,
"trouble-part-1": satel.TroublePart1,
"trouble-part-2": satel.TroublePart2,
"trouble-part-3": satel.TroublePart3,
"trouble-part-4": satel.TroublePart4,
"trouble-part-5": satel.TroublePart5,
"trouble-memory-part-1": satel.TroubleMemoryPart1,
"trouble-memory-part-2": satel.TroubleMemoryPart2,
"trouble-memory-part-3": satel.TroubleMemoryPart3,
"trouble-memory-part-4": satel.TroubleMemoryPart4,
"trouble-memory-part-5": satel.TroubleMemoryPart5,
"partition-with-violated-zones": satel.PartitionWithViolatedZones,
"zone-isolate": satel.ZoneIsolate,
}
func StringToSatelChangeType(s string) (satel.ChangeType, error) {
ct, ok := SATEL_STRING_TO_CHANGE_TYPE[s]
if !ok {
return 0, errors.New(fmt.Sprint("Unknown change type: ", s))
}
return ct, nil
}

22
satel_utils_test.go Normal file
View File

@ -0,0 +1,22 @@
package main
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestStringToSatelChangeType(t *testing.T) {
for _, ct := range SUPPORTED_CHANGE_TYPES {
str := ct.String()
new_ct, err := StringToSatelChangeType(str)
assert.NoError(t, err)
assert.Equal(t, ct, new_ct)
assert.Equal(t, new_ct.String(), str)
}
}
func TestStringToSatelChangeType_UnknownStringPanics(t *testing.T) {
_, err := StringToSatelChangeType("smród")
assert.Error(t, err, "")
}