implement remote calibration with downlinks
This commit is contained in:
parent
959c930af5
commit
d15653021f
|
|
@ -0,0 +1,125 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
"math"
|
||||||
|
"strings"
|
||||||
|
"strconv"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
const api_url="https://proxy1.lpn.swisscom.ch/thingpark/lrc/rest"
|
||||||
|
|
||||||
|
func MakePost(url string) {
|
||||||
|
req, err := http.NewRequest("POST", url, nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Error reading request. ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set headers
|
||||||
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
|
||||||
|
// Set client timeout
|
||||||
|
client := &http.Client{Timeout: time.Second * 10}
|
||||||
|
|
||||||
|
// Send request
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Error reading response. ", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
fmt.Println("response Status:", resp.Status)
|
||||||
|
fmt.Println("response Headers:", resp.Header)
|
||||||
|
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Error reading body. ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("%s\n", body)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ResetNodeToZero(deveui string, w1_0 int32, w2_0 int32) {
|
||||||
|
fmt.Printf("Called ResetNodeToZero for deveui %s\n", deveui)
|
||||||
|
s := fmt.Sprintf("%s/downlink?DevEUI=%s&FPort=1&Payload=00", api_url, deveui)
|
||||||
|
MakePost(s)
|
||||||
|
// values should be taken from next packet...
|
||||||
|
SetDownlinkCommand(deveui,"update_cal_from_node")
|
||||||
|
}
|
||||||
|
|
||||||
|
func CalibrateScale(deveui string, downlink_command string, w1 int32, w2 int32) {
|
||||||
|
fmt.Printf("Called CalibrateScale for deveui %s, downlink_command: %s\n", deveui, downlink_command)
|
||||||
|
var cur_cal_settings CalSettings
|
||||||
|
cur_cal_settings = GetCurrentCalibrationSettings(deveui)
|
||||||
|
var calibration_weight_gram int32
|
||||||
|
var calibration_weight2_gram int32
|
||||||
|
tokens := strings.Split(downlink_command," ")
|
||||||
|
if (len(tokens) < 2) {
|
||||||
|
// no value in gram included!
|
||||||
|
fmt.Printf("Error: invalid downlink_command: %s, examples: \"tare_a 10000\", \"tare_b 10000\", \"tare 10000 10000\" devuid: %s\n", downlink_command, deveui)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
n, err := strconv.ParseInt(tokens[1], 10, 32)
|
||||||
|
if err == nil {
|
||||||
|
calibration_weight_gram = int32(n)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Error: cannot get tare weight in gram: %s, deveui: %s\n", downlink_command, deveui)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len(tokens) > 2) {
|
||||||
|
n, err := strconv.ParseInt(tokens[2], 10, 32)
|
||||||
|
if err == nil {
|
||||||
|
calibration_weight2_gram = int32(n)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Error: cannot get tare weight2 in gram: %s, deveui: %s\n", downlink_command, deveui)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tokens[0] == "tare_a") {
|
||||||
|
new_w1_c := float32(w1 - cur_cal_settings.w1_0) / float32(calibration_weight_gram)
|
||||||
|
valstr := fmt.Sprintf("%08X%08X%08X%08X",uint32(cur_cal_settings.w1_0),uint32(cur_cal_settings.w2_0),math.Float32bits(new_w1_c),math.Float32bits(cur_cal_settings.w2_c))
|
||||||
|
s := fmt.Sprintf("%s/downlink?DevEUI=%s&FPort=1&Payload=01%s", api_url, deveui, valstr)
|
||||||
|
MakePost(s)
|
||||||
|
} else if (tokens[0] == "tare_b") {
|
||||||
|
new_w2_c := float32(w2 - cur_cal_settings.w2_0) / float32(calibration_weight_gram)
|
||||||
|
valstr := fmt.Sprintf("%08X%08X%08X%08X",uint32(cur_cal_settings.w1_0),uint32(cur_cal_settings.w2_0),math.Float32bits(cur_cal_settings.w2_c),math.Float32bits(new_w2_c))
|
||||||
|
s := fmt.Sprintf("%s/downlink?DevEUI=%s&FPort=1&Payload=01%s", api_url, deveui, valstr)
|
||||||
|
MakePost(s)
|
||||||
|
} else if (tokens[0] == "tare") {
|
||||||
|
new_w1_c := float32(w1 - cur_cal_settings.w1_0) / float32(calibration_weight_gram)
|
||||||
|
new_w2_c := float32(w2 - cur_cal_settings.w2_0) / float32(calibration_weight2_gram)
|
||||||
|
valstr := fmt.Sprintf("%08X%08X%08X%08X",uint32(cur_cal_settings.w1_0),uint32(cur_cal_settings.w2_0),math.Float32bits(new_w1_c),math.Float32bits(new_w2_c))
|
||||||
|
s := fmt.Sprintf("%s/downlink?DevEUI=%s&FPort=1&Payload=01%s", api_url, deveui, valstr)
|
||||||
|
MakePost(s)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Error: either use tare_a or tare_b or tare; deveui %s\n", deveui)
|
||||||
|
}
|
||||||
|
SetDownlinkCommand(deveui,"update_cal_from_node")
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateNodeCalibrationSettings(deveui string) {
|
||||||
|
fmt.Printf("Called UpdateNodeCalibrationSettings for deveui %s\n", deveui)
|
||||||
|
var cur_cal_settings CalSettings
|
||||||
|
cur_cal_settings = GetCurrentCalibrationSettings(deveui)
|
||||||
|
|
||||||
|
valstr := fmt.Sprintf("%08X%08X%08X%08X",uint32(cur_cal_settings.w1_0),uint32(cur_cal_settings.w2_0),math.Float32bits(cur_cal_settings.w1_c),math.Float32bits(cur_cal_settings.w2_c))
|
||||||
|
s := fmt.Sprintf("%s/downlink?DevEUI=%s&FPort=1&Payload=01%s", api_url, deveui, valstr)
|
||||||
|
MakePost(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateCalibrationSettingsFromNode(deveui string, w1_0 int32, w2_0 int32, w1_c float32, w2_c float32) {
|
||||||
|
fmt.Printf("Called UpdateCalibrationSettingsFromNode for deveui %s\n", deveui)
|
||||||
|
var new_cal_settings CalSettings
|
||||||
|
new_cal_settings.w1_0 = w1_0
|
||||||
|
new_cal_settings.w2_0 = w2_0
|
||||||
|
new_cal_settings.w1_c = w1_c
|
||||||
|
new_cal_settings.w2_c = w2_c
|
||||||
|
SetCurrentCalibrationSettings(deveui,new_cal_settings)
|
||||||
|
SetDownlinkCommand(deveui,"do_nothing")
|
||||||
|
}
|
||||||
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
|
"strings"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
@ -105,6 +106,37 @@ var file *os.File
|
||||||
var alertMap map[string]string
|
var alertMap map[string]string
|
||||||
var alertLogMap map[string]string
|
var alertLogMap map[string]string
|
||||||
|
|
||||||
|
func ProcessInitPacket(deveui string, w1_0 int32, w2_0 int32, w1_c float32, w2_c float32, w1 int32, w2 int32) {
|
||||||
|
var downlink_command string
|
||||||
|
|
||||||
|
fmt.Printf("Processing Init Packet for Deveui %s\n", deveui)
|
||||||
|
downlink_command = GetDownlinkCommand(deveui)
|
||||||
|
if (downlink_command == "do_nothing") {
|
||||||
|
// do nothing
|
||||||
|
fmt.Printf("Init Packet, downlink_command set to do_nothing (or not set at all), nothing to do... Deveui %s\n", deveui)
|
||||||
|
} else if (downlink_command == "tare_0") {
|
||||||
|
// reset node to 0
|
||||||
|
ResetNodeToZero(deveui, w1_0, w2_0)
|
||||||
|
} else if strings.HasPrefix(downlink_command, "tare_a ") {
|
||||||
|
// calibrate Scale A : tare_a <gram_a>
|
||||||
|
CalibrateScale(deveui, downlink_command, w1, w2)
|
||||||
|
} else if strings.HasPrefix(downlink_command, "tare_b ") {
|
||||||
|
// calibrate Scale B : tare_b <gram_b>
|
||||||
|
CalibrateScale(deveui, downlink_command, w1, w2)
|
||||||
|
} else if strings.HasPrefix(downlink_command, "tare ") {
|
||||||
|
// calibrate both Scale A and Scale B in on step : tare <gram_a> <gram_b>
|
||||||
|
CalibrateScale(deveui, downlink_command, w1, w2)
|
||||||
|
} else if (downlink_command == "update_cal_on_node") {
|
||||||
|
// update calibration settings on node
|
||||||
|
UpdateNodeCalibrationSettings(deveui)
|
||||||
|
} else if (downlink_command == "update_cal_from_node") {
|
||||||
|
// update calibration settings from node
|
||||||
|
UpdateCalibrationSettingsFromNode(deveui, w1_0, w2_0, w1_c, w2_c)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Error: Unknown downlink_command: %s (DevEUI: %s)\n", downlink_command, deveui)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func DecodePayload(s string, deveui string, devaddr string, lrrlat float32, lrrlon float32, write2file bool) {
|
func DecodePayload(s string, deveui string, devaddr string, lrrlat float32, lrrlon float32, write2file bool) {
|
||||||
var ba []byte
|
var ba []byte
|
||||||
var pl_1 payload_1
|
var pl_1 payload_1
|
||||||
|
|
@ -202,6 +234,7 @@ func DecodePayload(s string, deveui string, devaddr string, lrrlat float32, lrrl
|
||||||
|
|
||||||
WriteDatapoint(tfp,deveui,devaddr,pl_128.Vbat,pl_128.H,pl_128.P,w,pl_128.W1,pl_128.W2,pl_128.T,lrrlat,lrrlon,pl_128.Fw_version,pl_128.W1_0,pl_128.W2_0,pl_128.W1_C,pl_128.W2_C)
|
WriteDatapoint(tfp,deveui,devaddr,pl_128.Vbat,pl_128.H,pl_128.P,w,pl_128.W1,pl_128.W2,pl_128.T,lrrlat,lrrlon,pl_128.Fw_version,pl_128.W1_0,pl_128.W2_0,pl_128.W1_C,pl_128.W2_C)
|
||||||
}
|
}
|
||||||
|
ProcessInitPacket(deveui,pl_128.W1_0,pl_128.W2_0,pl_128.W1_C,pl_128.W2_C,pl_128.W1,pl_128.W2)
|
||||||
} else if (s[0:2] == "81") {
|
} else if (s[0:2] == "81") {
|
||||||
fmt.Printf("{\n")
|
fmt.Printf("{\n")
|
||||||
fmt.Printf(" version: %d,\n", pl_129.Version)
|
fmt.Printf(" version: %d,\n", pl_129.Version)
|
||||||
|
|
@ -250,13 +283,13 @@ func WriteDatapoint(mytime int64, deveui string, devaddr string, v uint8, h uint
|
||||||
|
|
||||||
sv := ""
|
sv := ""
|
||||||
if (v > 0) {
|
if (v > 0) {
|
||||||
sv = fmt.Sprintf(",v=%di,vp=%di,",int32(v)*7+2510,vp)
|
sv = fmt.Sprintf("v=%di,vp=%di,",int32(v)*7+2510,vp)
|
||||||
}
|
}
|
||||||
sfw := ""
|
sfw := ""
|
||||||
if (fw_version > 0) {
|
if (fw_version > 0) {
|
||||||
sfw = fmt.Sprintf(",fw_version=%di,w1=%di,w2=%di,w1_0=%d,w2_0=%d,w1_c=%f,w2_c=%f",fw_version,w1,w2,w1_0,w2_0,w1_c,w2_c)
|
sfw = fmt.Sprintf(",fw_version=%di,w1=%di,w2=%di,w1_0=%di,w2_0=%di,w1_c=%f,w2_c=%f",fw_version,w1,w2,w1_0,w2_0,w1_c,w2_c)
|
||||||
}
|
}
|
||||||
s = fmt.Sprintf("measurement,deveui=%s devaddr=\"%s\"%s,h=%di,p=%di,w=%di,t=%.1f,lrrlat=%f,lrrlon=%f%s %d\n",deveui,devaddr,sv,h,int32(p)+825,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,w*5,float32(t)/10,lrrlat,lrrlon,sfw,mytime*60*1000*1000*1000)
|
||||||
|
|
||||||
WriteStringToFile(s)
|
WriteStringToFile(s)
|
||||||
|
|
||||||
|
|
|
||||||
110
persistence.go
110
persistence.go
|
|
@ -3,6 +3,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
"strconv"
|
||||||
"github.com/gomodule/redigo/redis"
|
"github.com/gomodule/redigo/redis"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -11,6 +12,13 @@ var globalPool *redis.Pool
|
||||||
const lastvaluesPrefix string = "lastvalues:"
|
const lastvaluesPrefix string = "lastvalues:"
|
||||||
const devPrefix string = "dev:"
|
const devPrefix string = "dev:"
|
||||||
|
|
||||||
|
type CalSettings struct {
|
||||||
|
w1_0 int32
|
||||||
|
w2_0 int32
|
||||||
|
w1_c float32
|
||||||
|
w2_c float32
|
||||||
|
}
|
||||||
|
|
||||||
func newPool() *redis.Pool {
|
func newPool() *redis.Pool {
|
||||||
return &redis.Pool{
|
return &redis.Pool{
|
||||||
// Maximum number of idle connections in the pool.
|
// Maximum number of idle connections in the pool.
|
||||||
|
|
@ -187,3 +195,105 @@ func getSmsnumber(deveui string) string {
|
||||||
|
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetDownlinkCommand(deveui string) string {
|
||||||
|
// 0: do nothing...
|
||||||
|
res := "do_nothing"
|
||||||
|
|
||||||
|
if deveui == "" {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
conn := globalPool.Get()
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
downlink_command, err := redis.String(conn.Do("HGET", devPrefix+deveui, "downlink_command"))
|
||||||
|
if err == nil {
|
||||||
|
res = downlink_command
|
||||||
|
} else {
|
||||||
|
fmt.Println(err)
|
||||||
|
res = "do_nothing"
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetDownlinkCommand(deveui string, new_command string) error {
|
||||||
|
conn := globalPool.Get()
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
// SET object
|
||||||
|
_, err := conn.Do("HMSET", devPrefix+deveui, "downlink_command", new_command)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetCurrentCalibrationSettings(deveui string) CalSettings {
|
||||||
|
var res CalSettings
|
||||||
|
if deveui == "" {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
conn := globalPool.Get()
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
s_w1_0, err := redis.String(conn.Do("HGET", devPrefix+deveui, "w1_0"))
|
||||||
|
if err == nil {
|
||||||
|
n, err := strconv.ParseInt(s_w1_0, 10, 32)
|
||||||
|
if err == nil {
|
||||||
|
res.w1_0 = int32(n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s_w2_0, err := redis.String(conn.Do("HGET", devPrefix+deveui, "w2_0"))
|
||||||
|
if err == nil {
|
||||||
|
n, err := strconv.ParseInt(s_w2_0, 10, 32)
|
||||||
|
if err == nil {
|
||||||
|
res.w2_0 = int32(n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s_w1_c, err := redis.String(conn.Do("HGET", devPrefix+deveui, "w1_c"))
|
||||||
|
if err == nil {
|
||||||
|
f, err := strconv.ParseFloat(s_w1_c, 32)
|
||||||
|
if err == nil {
|
||||||
|
res.w1_c = float32(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s_w2_c, err := redis.String(conn.Do("HGET", devPrefix+deveui, "w2_c"))
|
||||||
|
if err == nil {
|
||||||
|
f, err := strconv.ParseFloat(s_w2_c, 32)
|
||||||
|
if err == nil {
|
||||||
|
res.w2_c = float32(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetCurrentCalibrationSettings(deveui string, cal_settings CalSettings) error {
|
||||||
|
if deveui == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
conn := globalPool.Get()
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
w1_0 := fmt.Sprintf("%d",cal_settings.w1_0)
|
||||||
|
w2_0 := fmt.Sprintf("%d",cal_settings.w2_0)
|
||||||
|
w1_c := fmt.Sprintf("%f",cal_settings.w1_c)
|
||||||
|
w2_c := fmt.Sprintf("%f",cal_settings.w2_c)
|
||||||
|
|
||||||
|
// SET object
|
||||||
|
_, err := conn.Do("HMSET", devPrefix+deveui, "w1_0",w1_0,"w2_0",w2_0,"w1_c",w1_c,"w2_c",w2_c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue