implement alerting, first iteration
This commit is contained in:
parent
4960fc86e9
commit
f66060bc7e
|
|
@ -0,0 +1,108 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func stopAlerting(deveui string) {
|
||||
myurl := fmt.Sprintf("https://proxy1.lpn.swisscom.ch/thingpark/lrc/rest/downlink?DevEUI=%s&FPort=2&Payload=0201", deveui)
|
||||
|
||||
req, err := http.NewRequest("POST", myurl, nil)
|
||||
if err != nil {
|
||||
log.Fatal("Error reading request. ", err)
|
||||
}
|
||||
|
||||
req.Header.Set("Content-type", "application/x-www-form-urlencoded")
|
||||
|
||||
client := &http.Client{Timeout: time.Second * 10}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Fatal("Error reading response. ", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Fatal("Error reading body. ", err)
|
||||
}
|
||||
|
||||
fmt.Printf("%s\n", body)
|
||||
}
|
||||
|
||||
func sendSMS(phonenumber string, alertMessage string) {
|
||||
myurl := fmt.Sprintf("https://api.smsapi.com/sms.do?to=%s&message=%s&from=mini-beieli&format=json", phonenumber, url.QueryEscape(alertMessage))
|
||||
|
||||
req, err := http.NewRequest("GET", myurl, nil)
|
||||
if err != nil {
|
||||
log.Fatal("Error reading request. ", err)
|
||||
}
|
||||
|
||||
req.Header.Set("Authorization", "Bearer IQ4vRG2JvNOmYmrYz6RuSwAanYZgd2hHGwtN62kq")
|
||||
|
||||
client := &http.Client{Timeout: time.Second * 10}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Fatal("Error reading response. ", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Fatal("Error reading body. ", err)
|
||||
}
|
||||
|
||||
fmt.Printf("%s\n", body)
|
||||
}
|
||||
|
||||
func sendAlert(deveui string, alertMessage string) {
|
||||
fmt.Printf("sendAlert: deveui=%s, message=%s\n", deveui, alertMessage)
|
||||
smsnumber := getSmsnumber(deveui)
|
||||
alarmactive := getDevAlarmactive(deveui)
|
||||
fmt.Printf("sendAlert: deveui=%s, smsnumber=%s, alarmactive=%s\n", deveui, smsnumber, alarmactive)
|
||||
if (smsnumber != "") && (alarmactive == "1") {
|
||||
// we strip of the leading +
|
||||
smsnumber = strings.Replace(smsnumber, "+", "", -1)
|
||||
sendSMS(smsnumber, alertMessage)
|
||||
} else {
|
||||
email := getEmail(deveui)
|
||||
fmt.Printf("sendEmail: deveui=%s, email=%s\n", deveui, email)
|
||||
sendEmail(email, alertMessage)
|
||||
}
|
||||
}
|
||||
|
||||
func DispatchAlert(deveui string, alertMessage string) {
|
||||
// first let's stop the alerting cyle on the Lora Network (every minute for one hour!)
|
||||
stopAlerting(deveui)
|
||||
|
||||
// we check if deveui exists
|
||||
if !(checkDevExists(deveui)) {
|
||||
fmt.Printf("Error: Deveui %s does not exist!", deveui)
|
||||
return
|
||||
}
|
||||
|
||||
// then we check if it expired
|
||||
if AboExpired(deveui) {
|
||||
fmt.Printf("Error: Abo for Deveui %s is expired!", deveui)
|
||||
return
|
||||
}
|
||||
|
||||
// then we check that an alert was not already sent out recently
|
||||
if AlertAlreadySentRecently(deveui) {
|
||||
fmt.Printf("Error: Alert for Deveui %s has already been sent!", deveui)
|
||||
return
|
||||
}
|
||||
|
||||
// then we make an entry that an alert was sent, this will expire automatically
|
||||
AddAlertAlreadySentRecently(deveui)
|
||||
|
||||
// then we send the alert
|
||||
sendAlert(deveui, alertMessage)
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"log"
|
||||
"net/smtp"
|
||||
)
|
||||
|
||||
func sendEmail(username, message string) {
|
||||
c, err := smtp.Dial("127.0.0.1:25")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
// Set the sender and recipient.
|
||||
c.Mail("info@wo-bisch.ch")
|
||||
c.Rcpt(username)
|
||||
// Send the email body.
|
||||
wc, err := c.Data()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer wc.Close()
|
||||
mail_message := "To: " + username + `
|
||||
Subject: ` + message + `
|
||||
|
||||
Lieber Benutzer von wo-bisch.ch
|
||||
|
||||
` + message + `
|
||||
--
|
||||
wo-bisch.ch`
|
||||
|
||||
buf := bytes.NewBufferString(mail_message)
|
||||
if _, err = buf.WriteTo(wc); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,202 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/gomodule/redigo/redis"
|
||||
"log"
|
||||
"time"
|
||||
)
|
||||
|
||||
var globalPool *redis.Pool
|
||||
|
||||
const alertsentPrefix string = "alertsent:"
|
||||
const devPrefix string = "dev:"
|
||||
|
||||
func newPool() *redis.Pool {
|
||||
return &redis.Pool{
|
||||
// Maximum number of idle connections in the pool.
|
||||
MaxIdle: 80,
|
||||
// max number of connections
|
||||
MaxActive: 12000,
|
||||
// Dial is an application supplied function for creating and
|
||||
// configuring a connection.
|
||||
Dial: func() (redis.Conn, error) {
|
||||
c, err := redis.Dial("tcp", ":6379")
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
return c, err
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// ping tests connectivity for redis (PONG should be returned)
|
||||
func ping(c redis.Conn) error {
|
||||
// Send PING command to Redis
|
||||
// PING command returns a Redis "Simple String"
|
||||
// Use redis.String to convert the interface type to string
|
||||
_, err := redis.String(c.Do("PING"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func initDB() {
|
||||
|
||||
// newPool returns a pointer to a redis.Pool
|
||||
pool := newPool()
|
||||
// get a connection from the globalPool (redis.Conn)
|
||||
conn := pool.Get()
|
||||
defer conn.Close()
|
||||
|
||||
globalPool = pool
|
||||
|
||||
// wir machen einen Connection Test
|
||||
ping(conn)
|
||||
}
|
||||
|
||||
func closeDB() {
|
||||
globalPool.Close()
|
||||
}
|
||||
|
||||
func getActiveUntil(deveui string) string {
|
||||
res := ""
|
||||
|
||||
if deveui == "" {
|
||||
return res
|
||||
}
|
||||
|
||||
conn := globalPool.Get()
|
||||
defer conn.Close()
|
||||
|
||||
activeuntil, err := redis.String(conn.Do("HGET", devPrefix+deveui, "active_until"))
|
||||
if err == nil {
|
||||
res = activeuntil
|
||||
} else {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func AboExpired(deveui string) bool {
|
||||
active_until := getActiveUntil(deveui)
|
||||
|
||||
layout := "02.01.2006"
|
||||
t, _ := time.Parse(layout, active_until)
|
||||
|
||||
return t.Before(time.Now())
|
||||
}
|
||||
|
||||
func checkDevExists(deveui string) bool {
|
||||
conn := globalPool.Get()
|
||||
defer conn.Close()
|
||||
|
||||
_, err := redis.String(conn.Do("GET", devPrefix+deveui))
|
||||
if err == redis.ErrNil {
|
||||
return false
|
||||
} else if err != nil {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func getDevAlias(deveui string) string {
|
||||
res := deveui
|
||||
|
||||
if deveui == "" {
|
||||
return res
|
||||
}
|
||||
|
||||
conn := globalPool.Get()
|
||||
defer conn.Close()
|
||||
|
||||
alias, err := redis.String(conn.Do("HGET", devPrefix+deveui, "alias"))
|
||||
if err == nil {
|
||||
res = alias
|
||||
} else {
|
||||
res = deveui
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func getDevAlarmactive(deveui string) string {
|
||||
res := "0"
|
||||
|
||||
if deveui == "" {
|
||||
return res
|
||||
}
|
||||
|
||||
conn := globalPool.Get()
|
||||
defer conn.Close()
|
||||
|
||||
alarmactive, err := redis.String(conn.Do("HGET", devPrefix+deveui, "alarmactive"))
|
||||
if err == nil {
|
||||
res = alarmactive
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func getSmsnumber(deveui string) string {
|
||||
res := ""
|
||||
if deveui == "" {
|
||||
return res
|
||||
}
|
||||
|
||||
conn := globalPool.Get()
|
||||
defer conn.Close()
|
||||
|
||||
smsnumber, err := redis.String(conn.Do("HGET", devPrefix+deveui, "smsnumber"))
|
||||
if err == nil {
|
||||
res = smsnumber
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func getEmail(deveui string) string {
|
||||
res := ""
|
||||
if deveui == "" {
|
||||
return res
|
||||
}
|
||||
|
||||
conn := globalPool.Get()
|
||||
defer conn.Close()
|
||||
|
||||
email, err := redis.String(conn.Do("HGET", devPrefix+deveui, "email"))
|
||||
if err == nil {
|
||||
res = email
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func AlertAlreadySentRecently(deveui string) bool {
|
||||
conn := globalPool.Get()
|
||||
defer conn.Close()
|
||||
|
||||
exists, _ := redis.Bool(conn.Do("EXISTS", alertsentPrefix+deveui))
|
||||
return exists
|
||||
}
|
||||
|
||||
func AddAlertAlreadySentRecently(deveui string) {
|
||||
conn := globalPool.Get()
|
||||
defer conn.Close()
|
||||
|
||||
_, err := conn.Do("SET", alertsentPrefix+deveui, "1")
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// we set an expiration time of three hours
|
||||
_, err1 := conn.Do("EXPIRE", alertsentPrefix+deveui, 600)
|
||||
|
||||
if err1 != nil {
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -92,10 +92,18 @@ func DecodePayload(s string, deveui string) {
|
|||
|
||||
vbat := (pl.AlarmBat & 0x3fff) // Battery Voltage in mV
|
||||
fw := 160 + (pl.Flag & 0x1f) // Firmware version; 5 bits
|
||||
alarm := (pl.AlarmBat & 0x4000) == 0x4000 // Alarm Bit
|
||||
|
||||
log.Printf("AlarmBit: %v", alarm)
|
||||
|
||||
mystring := fmt.Sprintf("measurement,deveui=%s lat=%.5f,lon=%.5f,vbat=%d,fw=%d %d\n", deveui, float32(pl.Latitude)/1000000.0, float32(pl.Longitude)/1000000.0, vbat, fw, (time.Now().Unix() * 1000 * 1000 * 1000))
|
||||
|
||||
WriteStringToFile(mystring, deveui)
|
||||
// we send an alert, when the alert bit is set
|
||||
if alarm {
|
||||
log.Printf("DispatchAlert (button pressed) for %s\n", deveui)
|
||||
DispatchAlert(deveui, "Alert button pressed!")
|
||||
}
|
||||
|
||||
} else {
|
||||
log.Printf("Payload is not >= 11 bytes (22 chars): %s", s)
|
||||
|
|
@ -103,6 +111,9 @@ func DecodePayload(s string, deveui string) {
|
|||
}
|
||||
|
||||
func main() {
|
||||
// Init Redis
|
||||
initDB()
|
||||
|
||||
// Open Output File
|
||||
f, err := os.OpenFile(outputfile, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
|
||||
file = f
|
||||
|
|
|
|||
Loading…
Reference in New Issue