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"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"strings"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
|
@ -105,6 +106,37 @@ var file *os.File
|
|||
var alertMap 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) {
|
||||
var ba []byte
|
||||
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)
|
||||
}
|
||||
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") {
|
||||
fmt.Printf("{\n")
|
||||
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 := ""
|
||||
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 := ""
|
||||
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)
|
||||
|
||||
|
|
|
|||
110
persistence.go
110
persistence.go
|
|
@ -3,6 +3,7 @@ package main
|
|||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
"strconv"
|
||||
"github.com/gomodule/redigo/redis"
|
||||
)
|
||||
|
||||
|
|
@ -11,6 +12,13 @@ var globalPool *redis.Pool
|
|||
const lastvaluesPrefix string = "lastvalues:"
|
||||
const devPrefix string = "dev:"
|
||||
|
||||
type CalSettings struct {
|
||||
w1_0 int32
|
||||
w2_0 int32
|
||||
w1_c float32
|
||||
w2_c float32
|
||||
}
|
||||
|
||||
func newPool() *redis.Pool {
|
||||
return &redis.Pool{
|
||||
// Maximum number of idle connections in the pool.
|
||||
|
|
@ -187,3 +195,105 @@ func getSmsnumber(deveui string) string {
|
|||
|
||||
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