Compare commits
10 Commits
6b95624b3e
...
c4610358f1
| Author | SHA1 | Date |
|---|---|---|
|
|
c4610358f1 | |
|
|
2c67bde970 | |
|
|
d7e6f84fe5 | |
|
|
7a7cb8d64e | |
|
|
dc6936912e | |
|
|
5f8fcea155 | |
|
|
bb4c713d3c | |
|
|
69c6900a77 | |
|
|
f3eb5dcc4e | |
|
|
b4eaa3fd16 |
|
|
@ -0,0 +1,12 @@
|
||||||
|
FROM golang:alpine AS builder
|
||||||
|
WORKDIR /build
|
||||||
|
ADD go.mod .
|
||||||
|
COPY . .
|
||||||
|
RUN go build
|
||||||
|
FROM alpine
|
||||||
|
RUN apk add --no-cache tzdata
|
||||||
|
ENV TZ=Europe/Zurich
|
||||||
|
WORKDIR /build
|
||||||
|
COPY --from=builder /build/mini-beieli-lorahandler /build/mini-beieli-lorahandler
|
||||||
|
CMD ["./mini-beieli-lorahandler"]
|
||||||
|
EXPOSE 8080
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
module nbit.ch/mini-beieli-lorahandler/v2
|
||||||
|
|
||||||
|
go 1.17
|
||||||
|
|
||||||
|
require github.com/gomodule/redigo v1.8.9
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/gomodule/redigo v1.8.9 h1:Sl3u+2BI/kk+VEatbj0scLdrFhjPmbxOc1myhDP41ws=
|
||||||
|
github.com/gomodule/redigo v1.8.9/go.mod h1:7ArFNvsTjH8GMMzB4uy1snslv2BwmginuMs06a1uzZE=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
69
main.go
69
main.go
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
@ -19,7 +20,7 @@ const (
|
||||||
MyDB = "beieliscaledb"
|
MyDB = "beieliscaledb"
|
||||||
username = "beieli"
|
username = "beieli"
|
||||||
password = "beieli4president"
|
password = "beieli4president"
|
||||||
outputfile = "/home/beieli/mini-beieli-lorahandler/mini-beieli-lorahandler.log"
|
outputfile = "/data/mini-beieli-lorahandler.log"
|
||||||
NOT_PLAUSIBLE_16 = 65535
|
NOT_PLAUSIBLE_16 = 65535
|
||||||
NOT_PLAUSIBLE_32 = 2147483647
|
NOT_PLAUSIBLE_32 = 2147483647
|
||||||
)
|
)
|
||||||
|
|
@ -213,6 +214,7 @@ func DecodePayload(s string, deveui string, devaddr string, lrrlat float32, lrrl
|
||||||
pl_130 = payload_130{}
|
pl_130 = payload_130{}
|
||||||
br := bytes.NewReader(ba)
|
br := bytes.NewReader(ba)
|
||||||
fmt.Printf("Payload String: %s\n", s)
|
fmt.Printf("Payload String: %s\n", s)
|
||||||
|
if len(s) > 2 {
|
||||||
if s[0:2] == "01" {
|
if s[0:2] == "01" {
|
||||||
err := binary.Read(br, binary.LittleEndian, &pl_1)
|
err := binary.Read(br, binary.LittleEndian, &pl_1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -340,32 +342,56 @@ func DecodePayload(s string, deveui string, devaddr string, lrrlat float32, lrrl
|
||||||
WriteDatapoint(tfp, deveui, devaddr, pl_2.Vbat, pl_2.H, pl_2.P, w, 0, 0, t, lrrlat, lrrlon, 0, 0, 0, 0, 0)
|
WriteDatapoint(tfp, deveui, devaddr, pl_2.Vbat, pl_2.H, pl_2.P, w, 0, 0, t, lrrlat, lrrlon, 0, 0, 0, 0, 0)
|
||||||
}
|
}
|
||||||
//t = t + int16(pl_2.TC1)
|
//t = t + int16(pl_2.TC1)
|
||||||
|
if valid_measurements == 2 {
|
||||||
|
w = pl_2.W8
|
||||||
|
} else {
|
||||||
w = w + uint16(pl_2.WC1)
|
w = w + uint16(pl_2.WC1)
|
||||||
|
}
|
||||||
if valid_measurements > 1 {
|
if valid_measurements > 1 {
|
||||||
WriteDatapoint(tfp+(step), deveui, devaddr, 0, 1, 0, w, 0, 0, t, lrrlat, lrrlon, 0, 0, 0, 0, 0)
|
WriteDatapoint(tfp+(step), deveui, devaddr, 0, 1, 0, w, 0, 0, t, lrrlat, lrrlon, 0, 0, 0, 0, 0)
|
||||||
}
|
}
|
||||||
t = t + int16(pl_2.TC2)
|
t = t + int16(pl_2.TC2)
|
||||||
|
if valid_measurements == 3 {
|
||||||
|
w = pl_2.W8
|
||||||
|
} else {
|
||||||
w = w + uint16(pl_2.WC2)
|
w = w + uint16(pl_2.WC2)
|
||||||
|
}
|
||||||
if valid_measurements > 2 {
|
if valid_measurements > 2 {
|
||||||
WriteDatapoint(tfp+(2*step), deveui, devaddr, 0, 1, 0, w, 0, 0, t, lrrlat, lrrlon, 0, 0, 0, 0, 0)
|
WriteDatapoint(tfp+(2*step), deveui, devaddr, 0, 1, 0, w, 0, 0, t, lrrlat, lrrlon, 0, 0, 0, 0, 0)
|
||||||
}
|
}
|
||||||
t = t + int16(pl_2.TC3)
|
t = t + int16(pl_2.TC3)
|
||||||
|
if valid_measurements == 4 {
|
||||||
|
w = pl_2.W8
|
||||||
|
} else {
|
||||||
w = w + uint16(pl_2.WC3)
|
w = w + uint16(pl_2.WC3)
|
||||||
|
}
|
||||||
if valid_measurements > 3 {
|
if valid_measurements > 3 {
|
||||||
WriteDatapoint(tfp+(3*step), deveui, devaddr, 0, 1, 0, w, 0, 0, t, lrrlat, lrrlon, 0, 0, 0, 0, 0)
|
WriteDatapoint(tfp+(3*step), deveui, devaddr, 0, 1, 0, w, 0, 0, t, lrrlat, lrrlon, 0, 0, 0, 0, 0)
|
||||||
}
|
}
|
||||||
t = t + int16(pl_2.TC4)
|
t = t + int16(pl_2.TC4)
|
||||||
|
if valid_measurements == 5 {
|
||||||
|
w = pl_2.W8
|
||||||
|
} else {
|
||||||
w = w + uint16(pl_2.WC4)
|
w = w + uint16(pl_2.WC4)
|
||||||
|
}
|
||||||
if valid_measurements > 4 {
|
if valid_measurements > 4 {
|
||||||
WriteDatapoint(tfp+(4*step), deveui, devaddr, 0, 1, 0, w, 0, 0, t, lrrlat, lrrlon, 0, 0, 0, 0, 0)
|
WriteDatapoint(tfp+(4*step), deveui, devaddr, 0, 1, 0, w, 0, 0, t, lrrlat, lrrlon, 0, 0, 0, 0, 0)
|
||||||
}
|
}
|
||||||
t = t + int16(pl_2.TC5)
|
t = t + int16(pl_2.TC5)
|
||||||
|
if valid_measurements == 6 {
|
||||||
|
w = pl_2.W8
|
||||||
|
} else {
|
||||||
w = w + uint16(pl_2.WC5)
|
w = w + uint16(pl_2.WC5)
|
||||||
|
}
|
||||||
if valid_measurements > 5 {
|
if valid_measurements > 5 {
|
||||||
WriteDatapoint(tfp+(5*step), deveui, devaddr, 0, 1, 0, w, 0, 0, t, lrrlat, lrrlon, 0, 0, 0, 0, 0)
|
WriteDatapoint(tfp+(5*step), deveui, devaddr, 0, 1, 0, w, 0, 0, t, lrrlat, lrrlon, 0, 0, 0, 0, 0)
|
||||||
}
|
}
|
||||||
t = t + int16(pl_2.TC6)
|
t = t + int16(pl_2.TC6)
|
||||||
|
if valid_measurements == 7 {
|
||||||
|
w = pl_2.W8
|
||||||
|
} else {
|
||||||
w = w + uint16(pl_2.WC6)
|
w = w + uint16(pl_2.WC6)
|
||||||
|
}
|
||||||
if valid_measurements > 6 {
|
if valid_measurements > 6 {
|
||||||
WriteDatapoint(tfp+(6*step), deveui, devaddr, 0, 1, 0, w, 0, 0, t, lrrlat, lrrlon, 0, 0, 0, 0, 0)
|
WriteDatapoint(tfp+(6*step), deveui, devaddr, 0, 1, 0, w, 0, 0, t, lrrlat, lrrlon, 0, 0, 0, 0, 0)
|
||||||
}
|
}
|
||||||
|
|
@ -478,6 +504,9 @@ func DecodePayload(s string, deveui string, devaddr string, lrrlat float32, lrrl
|
||||||
WriteStringToFile(val2, deveui, false)
|
WriteStringToFile(val2, deveui, false)
|
||||||
delete(alertLogMap, deveui)
|
delete(alertLogMap, deveui)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Payload String is not longer that 2 chars, ignore it\n")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsDayTime() bool {
|
func IsDayTime() bool {
|
||||||
|
|
@ -516,7 +545,7 @@ func WriteDatapoint(mytime int64, deveui string, devaddr string, v uint8, h uint
|
||||||
s = fmt.Sprintf("measurement,deveui=%s devaddr=\"%s\",%sh=%di,p=%di,w=%di,t=%.1f,lrrlat=%f,lrrlon=%f%s %d\n", deveui, devaddr, sv, h, int32(p)+825, uint32(w)*5, float32(t)/10, lrrlat, lrrlon, sfw, mytime*60*1000*1000*1000)
|
s = fmt.Sprintf("measurement,deveui=%s devaddr=\"%s\",%sh=%di,p=%di,w=%di,t=%.1f,lrrlat=%f,lrrlon=%f%s %d\n", deveui, devaddr, sv, h, int32(p)+825, uint32(w)*5, float32(t)/10, lrrlat, lrrlon, sfw, mytime*60*1000*1000*1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
implausible = (w1 == NOT_PLAUSIBLE_32) || (w2 == NOT_PLAUSIBLE_32) || (w == NOT_PLAUSIBLE_16)
|
implausible = (w1 == NOT_PLAUSIBLE_32) || (w2 == NOT_PLAUSIBLE_32) || (w == NOT_PLAUSIBLE_16) || (w == 0)
|
||||||
|
|
||||||
WriteStringToFile(s, deveui, implausible)
|
WriteStringToFile(s, deveui, implausible)
|
||||||
|
|
||||||
|
|
@ -530,6 +559,38 @@ func WriteDatapoint(mytime int64, deveui string, devaddr string, v uint8, h uint
|
||||||
location, _ := time.LoadLocation("Europe/Zurich")
|
location, _ := time.LoadLocation("Europe/Zurich")
|
||||||
alertMap[deveui] = fmt.Sprintf("*** Schwarmalarm ***\n%s\n%s\nGewichtsverlust: %d g", getDevAlias(deveui), time.Unix(mytime*60, 0).In(location).Format("02.01.2006 15:04"), w_loss)
|
alertMap[deveui] = fmt.Sprintf("*** Schwarmalarm ***\n%s\n%s\nGewichtsverlust: %d g", getDevAlias(deveui), time.Unix(mytime*60, 0).In(location).Format("02.01.2006 15:04"), w_loss)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// minmax Alert
|
||||||
|
fmt.Println("debug minmax alert")
|
||||||
|
minmax := getDevMinmax(deveui)
|
||||||
|
fmt.Printf("debug getDevMinmax: minmax = %s\n", minmax)
|
||||||
|
if minmax != "0,0" {
|
||||||
|
tokens := strings.Split(minmax, ",")
|
||||||
|
if len(tokens) == 2 {
|
||||||
|
min, _ := strconv.ParseInt(tokens[0], 10, 32)
|
||||||
|
max, _ := strconv.ParseInt(tokens[1], 10, 32)
|
||||||
|
fmt.Printf("debug min: %d, max: %d\n", min, max)
|
||||||
|
minmaxstatus := GetMinMaxStatus(deveui)
|
||||||
|
fmt.Printf("debug minmaxstatus: %s\n", minmaxstatus)
|
||||||
|
if (w_gram < uint32(min)) && (minmaxstatus != "MINALERT") {
|
||||||
|
fmt.Printf("debug minalert\n")
|
||||||
|
SetMinMaxStatus(deveui, "MINALERT")
|
||||||
|
alertLogMap[deveui] = fmt.Sprintf("alert,deveui=%s reason=\"minmaxlarm\",w=%di,w_min=%di %d\n", deveui, w_gram, min, mytime*60*1000*1000*1000)
|
||||||
|
location, _ := time.LoadLocation("Europe/Zurich")
|
||||||
|
alertMap[deveui] = fmt.Sprintf("*** Min/Max-Alarm ***\n%s\n%s\nUnterschreiten des Minimalgewichts: %d g (Minimal: %d g)", getDevAlias(deveui), time.Unix(mytime*60, 0).In(location).Format("02.01.2006 15:04"), w_gram, min)
|
||||||
|
} else if (w_gram > uint32(max)) && (minmaxstatus != "MAXALERT") {
|
||||||
|
fmt.Printf("debug maxalert\n")
|
||||||
|
SetMinMaxStatus(deveui, "MAXALERT")
|
||||||
|
alertLogMap[deveui] = fmt.Sprintf("alert,deveui=%s reason=\"minmaxlarm\",w=%di,w_max=%di %d\n", deveui, w_gram, max, mytime*60*1000*1000*1000)
|
||||||
|
location, _ := time.LoadLocation("Europe/Zurich")
|
||||||
|
alertMap[deveui] = fmt.Sprintf("*** Min/Max-Alarm ***\n%s\n%s\nUeberschreiten des Maximalgewichts: %d g (Maximal: %d g)", getDevAlias(deveui), time.Unix(mytime*60, 0).In(location).Format("02.01.2006 15:04"), w_gram, max)
|
||||||
|
} else if (w_gram > uint32(min+100)) && (w_gram < uint32(max-100)) {
|
||||||
|
fmt.Printf("debug resettonormal\n")
|
||||||
|
SetMinMaxStatus(deveui, "NORMAL")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -549,9 +610,9 @@ func WriteStringToFile(s string, deveui string, implausible bool) {
|
||||||
|
|
||||||
// Also write to individual files
|
// Also write to individual files
|
||||||
datestr := time.Now().Format("2006-01")
|
datestr := time.Now().Format("2006-01")
|
||||||
individual_file := "/home/beieli/mini-beieli-lorahandler/logs/" + deveui + "-" + datestr + ".log"
|
individual_file := "/data/logs/" + deveui + "-" + datestr + ".log"
|
||||||
if implausible {
|
if implausible {
|
||||||
individual_file = "/home/beieli/mini-beieli-lorahandler/logs/" + "implausible" + "-" + datestr + ".log"
|
individual_file = "/data/logs/" + "implausible" + "-" + datestr + ".log"
|
||||||
}
|
}
|
||||||
|
|
||||||
fi, err := os.OpenFile(individual_file, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
|
fi, err := os.OpenFile(individual_file, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gomodule/redigo/redis"
|
"github.com/gomodule/redigo/redis"
|
||||||
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
@ -12,6 +13,14 @@ var globalPool *redis.Pool
|
||||||
const lastvaluesPrefix string = "lastvalues:"
|
const lastvaluesPrefix string = "lastvalues:"
|
||||||
const devPrefix string = "dev:"
|
const devPrefix string = "dev:"
|
||||||
|
|
||||||
|
func getenv(key, fallback string) string {
|
||||||
|
value := os.Getenv(key)
|
||||||
|
if len(value) == 0 {
|
||||||
|
return fallback
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
type CalSettings struct {
|
type CalSettings struct {
|
||||||
w1_0 int32
|
w1_0 int32
|
||||||
w2_0 int32
|
w2_0 int32
|
||||||
|
|
@ -28,7 +37,7 @@ func newPool() *redis.Pool {
|
||||||
// Dial is an application supplied function for creating and
|
// Dial is an application supplied function for creating and
|
||||||
// configuring a connection.
|
// configuring a connection.
|
||||||
Dial: func() (redis.Conn, error) {
|
Dial: func() (redis.Conn, error) {
|
||||||
c, err := redis.Dial("tcp", ":6379")
|
c, err := redis.Dial("tcp", getenv("REDIS_CONNECTION_STRING", ":6379"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err.Error())
|
panic(err.Error())
|
||||||
}
|
}
|
||||||
|
|
@ -195,6 +204,26 @@ func getSmsnumber(deveui string) string {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getDevMinmax(deveui string) string {
|
||||||
|
res := "0,0"
|
||||||
|
|
||||||
|
if deveui == "" {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
conn := globalPool.Get()
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
minmax, err := redis.String(conn.Do("HGET", devPrefix+deveui, "minmax"))
|
||||||
|
if err == nil {
|
||||||
|
res = minmax
|
||||||
|
} else {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
func GetDownlinkCommand(deveui string) string {
|
func GetDownlinkCommand(deveui string) string {
|
||||||
// 0: do nothing...
|
// 0: do nothing...
|
||||||
res := "do_nothing"
|
res := "do_nothing"
|
||||||
|
|
@ -217,6 +246,37 @@ func GetDownlinkCommand(deveui string) string {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SetMinMaxStatus(deveui string, status string) error {
|
||||||
|
conn := globalPool.Get()
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
// SET object
|
||||||
|
_, err := conn.Do("HMSET", devPrefix+deveui, "minmaxstatus", status)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetMinMaxStatus(deveui string) string {
|
||||||
|
res := "NORMAL"
|
||||||
|
|
||||||
|
if deveui == "" {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
conn := globalPool.Get()
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
minmax, err := redis.String(conn.Do("HGET", devPrefix+deveui, "minmaxstatus"))
|
||||||
|
if err == nil {
|
||||||
|
res = minmax
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
func SetDownlinkCommand(deveui string, new_command string) error {
|
func SetDownlinkCommand(deveui string, new_command string) error {
|
||||||
conn := globalPool.Get()
|
conn := globalPool.Get()
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue