2024-02-08 18:23:46 +00:00
package main
import (
2024-02-09 22:32:32 +00:00
"flag"
2024-02-08 18:23:46 +00:00
"fmt"
2024-02-19 18:52:40 +00:00
"html/template"
2024-02-11 21:48:05 +00:00
"log"
2024-02-08 18:23:46 +00:00
"net"
2024-02-09 22:32:32 +00:00
"os"
2024-02-08 19:57:16 +00:00
"strconv"
2024-02-09 22:32:32 +00:00
"strings"
"sync"
"time"
2024-02-08 18:23:46 +00:00
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
2024-02-09 22:32:32 +00:00
"github.com/probakowski/go-satel"
2024-02-08 18:23:46 +00:00
)
2024-02-09 22:32:32 +00:00
const (
2024-02-10 23:13:31 +00:00
MessageNotMoreOftenThanSeconds = 15
2024-02-28 20:26:20 +00:00
PersistenceFilename = "hs_wro_last_seen.bin"
2024-02-09 22:32:32 +00:00
)
2024-02-10 23:13:31 +00:00
type TgSender struct {
bot * tgbotapi . BotAPI
2024-02-09 22:32:32 +00:00
}
2024-02-19 18:52:40 +00:00
func ( self TgSender ) Send ( msg GenericMessage , tpl * template . Template ) error {
chatIds := msg . ChatIds . GetTgIds ( )
2024-02-18 08:42:27 +00:00
if chatIds == nil {
return nil
}
2024-02-19 18:52:40 +00:00
message := msg . Format ( tpl )
2024-02-18 08:42:27 +00:00
for _ , chatId := range * chatIds {
toSend := tgbotapi . NewMessage ( chatId , message )
2024-02-18 16:28:32 +00:00
toSend . ParseMode = "HTML"
2024-02-18 08:42:27 +00:00
_ , err := self . bot . Send ( toSend )
if err != nil {
return err
}
}
return nil
2024-02-10 06:51:36 +00:00
}
2024-02-18 16:28:32 +00:00
func sendTgMessage ( tgEvents chan GenericMessage , msg MsgContent , chatId int64 ) {
tgEvents <- GenericMessage { TgChatId { chatId } , [ ] MsgContent { msg } }
2024-02-10 06:51:36 +00:00
}
2024-02-11 10:51:41 +00:00
type RealSleeper struct {
duration time . Duration
}
func ( self RealSleeper ) Sleep ( ch chan <- interface { } ) {
2024-02-11 21:51:33 +00:00
go func ( ) {
time . Sleep ( self . duration )
ch <- nil
} ( )
2024-02-11 10:51:41 +00:00
}
2024-02-18 18:00:49 +00:00
func getCmdLineParams ( logger * log . Logger ) ( string , [ ] int64 , [ ] satel . ChangeType , [ ] int ) {
2024-02-11 13:56:03 +00:00
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." )
2024-02-18 17:44:08 +00:00
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." )
2024-02-18 18:00:49 +00:00
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." )
2024-02-08 18:23:46 +00:00
flag . Parse ( )
2024-02-11 13:56:03 +00:00
if len ( * satelApiAddr ) == 0 || len ( * satelApiPort ) == 0 || len ( * chatIdRaw ) == 0 {
2024-02-11 21:48:05 +00:00
logger . Fatal ( "Use --satel-addr=ADDR, --satel-port=PORT and --tg-chat-id=CHAT_ID command line flags to continue." )
2024-02-08 18:23:46 +00:00
}
2024-02-11 13:56:03 +00:00
chatIdsStrings := strings . Split ( * chatIdRaw , "," )
var chatIds [ ] int64
for _ , chatIdStr := range chatIdsStrings {
chatId , err := strconv . ParseInt ( chatIdStr , 10 , 64 )
2024-02-08 19:57:16 +00:00
if err != nil {
2024-02-11 21:48:05 +00:00
logger . Fatalf ( "Tried to use a non-int value for one of tg_chatIds: %s. That's bad." , chatIdStr )
2024-02-08 19:57:16 +00:00
}
2024-02-11 13:56:03 +00:00
chatIds = append ( chatIds , chatId )
2024-02-08 19:57:16 +00:00
}
2024-02-18 17:44:08 +00:00
allowedTypesStrings := strings . Split ( * allowedTypesRaw , "," )
var allowedTypes [ ] satel . ChangeType
for _ , allowedTypeStr := range allowedTypesStrings {
2024-02-18 18:19:10 +00:00
if len ( allowedTypeStr ) == 0 {
continue
}
2024-02-18 17:44:08 +00:00
allowedType , err := StringToSatelChangeType ( allowedTypeStr )
if err != nil {
logger . Fatalf ( "Error trying to understand an allowed type: %s." , err )
}
allowedTypes = append ( allowedTypes , allowedType )
}
2024-02-18 18:00:49 +00:00
allowedIndexesStrings := strings . Split ( * allowedIndexesRaw , "," )
var allowedIndexes [ ] int
for _ , allowedIndexStr := range allowedIndexesStrings {
2024-02-18 18:19:10 +00:00
if len ( allowedIndexStr ) == 0 {
continue
}
2024-02-18 18:00:49 +00:00
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 ) )
}
2024-02-08 18:23:46 +00:00
2024-02-11 13:56:03 +00:00
satelAddr := fmt . Sprintf ( "%s:%s" , * satelApiAddr , * satelApiPort )
2024-02-18 18:00:49 +00:00
return satelAddr , chatIds , allowedTypes , allowedIndexes
2024-02-11 13:56:03 +00:00
}
func makeSatel ( satelAddr string ) * satel . Satel {
satelConn , err := net . Dial ( "tcp" , satelAddr )
2024-02-08 18:23:46 +00:00
if err != nil {
panic ( err )
}
2024-02-11 13:56:03 +00:00
return satel . NewConfig ( satelConn , satel . Config { EventsQueueSize : 10 } )
}
func main ( ) {
var (
wg sync . WaitGroup
tgEvents = make ( chan GenericMessage , 100 )
sleeper = RealSleeper { time . Second * MessageNotMoreOftenThanSeconds }
2024-02-11 21:48:05 +00:00
logger = log . New ( os . Stderr , "Main" , log . Lmicroseconds )
2024-02-11 13:56:03 +00:00
)
2024-02-18 18:00:49 +00:00
satelAddr , chatIds , allowedTypes , allowedIndexes := getCmdLineParams ( logger )
2024-02-11 13:56:03 +00:00
s := makeSatel ( satelAddr )
2024-02-11 21:48:05 +00:00
logger . Printf ( "Connected to Satel: %s" , satelAddr )
2024-02-11 13:56:03 +00:00
2024-02-08 18:23:46 +00:00
bot , err := tgbotapi . NewBotAPI ( os . Getenv ( "TELEGRAM_APITOKEN" ) )
2024-02-09 22:32:32 +00:00
if err != nil {
panic ( err )
}
2024-02-11 21:48:05 +00:00
logger . Print ( "Created Telegram Bot API client" )
2024-02-09 22:32:32 +00:00
2024-02-10 23:13:31 +00:00
tgSender := TgSender { bot }
2024-02-18 16:28:32 +00:00
2024-02-19 18:52:40 +00:00
tpl := template . Must ( template . New ( "TelegramMessage" ) . Parse ( TelegramMessageTemplate ) )
2024-02-28 20:26:20 +00:00
dataStore := MakeDataStore ( log . New ( os . Stderr , "DataStore" , log . Lmicroseconds ) , PersistenceFilename )
2024-02-18 16:28:32 +00:00
Consume (
SendToTg (
tgSenderWorker ( tgEvents , & wg , sleeper , log . New ( os . Stderr , "TgSender" , log . Lmicroseconds ) ) ,
2024-02-19 18:52:40 +00:00
tgSender , & wg , log . New ( os . Stderr , "SendToTg" , log . Lmicroseconds ) , tpl ) )
2024-02-18 16:28:32 +00:00
2024-02-18 18:36:54 +00:00
go CloseSatelOnCtrlC ( s )
2024-02-18 18:00:49 +00:00
for e := range FilterByIndex ( FilterByType (
2024-02-28 20:26:20 +00:00
FilterByLastSeen ( s . Events , & dataStore , log . New ( os . Stderr , "FilterByLastSeen" , log . Lmicroseconds ) ) ,
2024-02-18 18:00:49 +00:00
allowedTypes ) ,
allowedIndexes ) {
2024-02-11 21:56:58 +00:00
logger . Print ( "Received change from SATEL: " , e )
2024-02-18 16:28:32 +00:00
for _ , chatId := range chatIds {
2024-02-19 18:52:40 +00:00
sendTgMessage ( tgEvents , MsgContent { e } , chatId )
2024-02-18 16:28:32 +00:00
}
2024-02-08 18:23:46 +00:00
}
2024-02-09 22:32:32 +00:00
2024-02-11 13:56:03 +00:00
close ( tgEvents )
2024-02-09 22:32:32 +00:00
wg . Wait ( )
2024-02-08 18:23:46 +00:00
}