Possibility to filter by ChangeType

command_handler
Michał Rudowicz 2024-02-18 18:44:08 +01:00
rodzic 079e32e893
commit ab5bd412f2
6 zmienionych plików z 228 dodań i 13 usunięć

Wyświetl plik

@ -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
```
### 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
Set the `OMIT_TG` environment variable to, well, omit sending anything over to Telegram and just see the logs instead.

Wyświetl plik

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

Wyświetl plik

@ -39,6 +39,32 @@ func TestSatelEventTypeFiltering(t *testing.T) {
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) {
f, err := os.CreateTemp("", "TestSatelLastSeenFiltering")
assert.NoError(t, err)

20
main.go
Wyświetl plik

@ -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")
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.")
flag.Parse()
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)
}
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)
return satelAddr, chatIds
return satelAddr, chatIds, allowedTypes
}
func makeSatel(satelAddr string) *satel.Satel {
@ -107,7 +117,7 @@ func main() {
logger = log.New(os.Stderr, "Main", log.Lmicroseconds)
)
satelAddr, chatIds := getCmdLineParams(logger)
satelAddr, chatIds, allowedTypes := getCmdLineParams(logger)
s := makeSatel(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)),
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)
for _, chatId := range chatIds {
sendTgMessage(tgEvents, SatelMsgContent{e}, chatId)

100
satel_utils.go 100644
Wyświetl plik

@ -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
}

Wyświetl plik

@ -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, "")
}