Possibility to filter by ChangeType
This commit is contained in:
parent
079e32e893
commit
ab5bd412f2
45
README.md
45
README.md
|
@ -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.
|
||||||
|
|
10
filters.go
10
filters.go
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
20
main.go
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -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, "")
|
||||||
|
}
|
Loading…
Reference in New Issue