169 lines
3.8 KiB
Go
169 lines
3.8 KiB
Go
|
|
package binary_phasor
|
||
|
|
|
||
|
|
import (
|
||
|
|
"encoding/binary"
|
||
|
|
"errors"
|
||
|
|
"math"
|
||
|
|
"strconv"
|
||
|
|
"strings"
|
||
|
|
"testing"
|
||
|
|
"time"
|
||
|
|
|
||
|
|
"github.com/influxdata/telegraf"
|
||
|
|
"github.com/influxdata/telegraf/metric"
|
||
|
|
"github.com/influxdata/telegraf/testutil"
|
||
|
|
)
|
||
|
|
|
||
|
|
func generatePhasorBinary(iou byte, pf int, ts uint32) ([]byte, error) {
|
||
|
|
var data []byte
|
||
|
|
var chanNum byte
|
||
|
|
switch iou {
|
||
|
|
case 1:
|
||
|
|
data = make([]byte, 0, 11306)
|
||
|
|
chanNum = 14
|
||
|
|
case 2:
|
||
|
|
data = make([]byte, 0, 14106)
|
||
|
|
chanNum = 15
|
||
|
|
default:
|
||
|
|
return nil, errors.New("not supported type")
|
||
|
|
}
|
||
|
|
|
||
|
|
data = binary.LittleEndian.AppendUint32(data, ts)
|
||
|
|
data = append(data, iou)
|
||
|
|
data = append(data, chanNum)
|
||
|
|
|
||
|
|
for i := range 8 {
|
||
|
|
for range pf {
|
||
|
|
data = binary.LittleEndian.AppendUint64(data, math.Float64bits(float64(i)))
|
||
|
|
data = binary.LittleEndian.AppendUint64(data, math.Float64bits(float64(i)))
|
||
|
|
data = binary.LittleEndian.AppendUint64(data, math.Float64bits(float64(i)))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
for range pf {
|
||
|
|
data = append(data, 0xAA) // 1010 1010
|
||
|
|
}
|
||
|
|
for range pf {
|
||
|
|
data = append(data, 0x55) // 0101 0101
|
||
|
|
}
|
||
|
|
|
||
|
|
switch iou {
|
||
|
|
case 1:
|
||
|
|
for i := range 4 {
|
||
|
|
for range pf {
|
||
|
|
data = binary.LittleEndian.AppendUint64(data, math.Float64bits(float64(i+8)))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
case 2:
|
||
|
|
for i := range 2 {
|
||
|
|
for range pf {
|
||
|
|
data = binary.LittleEndian.AppendUint64(data, math.Float64bits(float64(i+8)))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
for i := range 3 {
|
||
|
|
for range pf {
|
||
|
|
data = binary.LittleEndian.AppendUint64(data, math.Float64bits(float64(i+10)))
|
||
|
|
data = binary.LittleEndian.AppendUint64(data, math.Float64bits(float64(i+10)))
|
||
|
|
data = binary.LittleEndian.AppendUint64(data, math.Float64bits(float64(i+10)))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
default:
|
||
|
|
return nil, errors.New("not supported type")
|
||
|
|
}
|
||
|
|
|
||
|
|
return data, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func generateExpectedMetrics(device string, iou byte, pf int, ts uint32) ([]telegraf.Metric, error) {
|
||
|
|
metrics := make([]telegraf.Metric, pf)
|
||
|
|
|
||
|
|
var fields map[string]interface{}
|
||
|
|
measurement := ""
|
||
|
|
switch iou {
|
||
|
|
case 1:
|
||
|
|
measurement = "current"
|
||
|
|
fields = make(map[string]interface{}, 44)
|
||
|
|
case 2:
|
||
|
|
measurement = "voltage"
|
||
|
|
fields = make(map[string]interface{}, 51)
|
||
|
|
default:
|
||
|
|
return nil, errors.New("not supported type")
|
||
|
|
}
|
||
|
|
|
||
|
|
for i := range metrics {
|
||
|
|
m := metric.New(
|
||
|
|
measurement,
|
||
|
|
map[string]string{"device": device},
|
||
|
|
fields,
|
||
|
|
time.Unix(int64(ts), int64(i*1e9/pf)),
|
||
|
|
)
|
||
|
|
|
||
|
|
for cj := range 8 {
|
||
|
|
chanNo := strconv.Itoa(cj + 1)
|
||
|
|
m.AddField("c"+chanNo+"_amp", float64(cj))
|
||
|
|
m.AddField("c"+chanNo+"_pa", float64(cj))
|
||
|
|
m.AddField("c"+chanNo+"_rms", float64(cj))
|
||
|
|
}
|
||
|
|
|
||
|
|
for cj := range 8 {
|
||
|
|
chanNo := strconv.Itoa(cj + 1)
|
||
|
|
m.AddField("i"+chanNo, uint8((1+math.Pow(-1, float64(cj+1)))/2))
|
||
|
|
}
|
||
|
|
for cj := range 8 {
|
||
|
|
chanNo := strconv.Itoa(cj + 1 + 8)
|
||
|
|
m.AddField("i"+chanNo, uint8((1+math.Pow(-1, float64(cj)))/2))
|
||
|
|
}
|
||
|
|
|
||
|
|
switch iou {
|
||
|
|
case 1:
|
||
|
|
for cj, channel := range []string{"p", "q", "s", "pf"} {
|
||
|
|
m.AddField(channel, float64(cj+8))
|
||
|
|
}
|
||
|
|
case 2:
|
||
|
|
for cj, channel := range []string{"f", "df"} {
|
||
|
|
m.AddField(channel, float64(cj+8))
|
||
|
|
}
|
||
|
|
for cj, channel := range []string{"uab", "ubc", "uca"} {
|
||
|
|
m.AddField(channel+"_amp", float64(cj+10))
|
||
|
|
m.AddField(channel+"_pa", float64(cj+10))
|
||
|
|
m.AddField(channel+"_rms", float64(cj+10))
|
||
|
|
}
|
||
|
|
default:
|
||
|
|
return nil, errors.New("not supported type")
|
||
|
|
}
|
||
|
|
|
||
|
|
metrics[i] = m
|
||
|
|
}
|
||
|
|
|
||
|
|
return metrics, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestParse(t *testing.T) {
|
||
|
|
topic := "ssu001_Phasor"
|
||
|
|
device, _ := strings.CutSuffix(topic, "_Phasor")
|
||
|
|
|
||
|
|
for iou := range 2 {
|
||
|
|
ts := uint32(time.Now().Unix())
|
||
|
|
|
||
|
|
data, err := generatePhasorBinary(byte(iou+1), 50, ts)
|
||
|
|
if err != nil {
|
||
|
|
t.FailNow()
|
||
|
|
}
|
||
|
|
|
||
|
|
expected, err := generateExpectedMetrics(device, byte(iou+1), 50, ts)
|
||
|
|
if err != nil {
|
||
|
|
t.FailNow()
|
||
|
|
}
|
||
|
|
|
||
|
|
parser := new(Parser)
|
||
|
|
parser.Init()
|
||
|
|
|
||
|
|
actual, err := parser.Parse(data, topic)
|
||
|
|
if err != nil {
|
||
|
|
t.FailNow()
|
||
|
|
}
|
||
|
|
|
||
|
|
testutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime(), testutil.SortMetrics())
|
||
|
|
}
|
||
|
|
}
|