Hey, I’m writing easy server to hook up with dlms meters and get readings from them, however faceing with corrupted buffer downside on high-load, however every thing wonderful on few connections. It’s all what i’m doing.
(Don’t take note of the exhausting code, the thought was to check)
bundle inner
import (
"encoding/hex"
"fmt"
"internet"
"regexp"
"strconv"
"strings"
"sync"
"time"
)
kind Meter struct {
socket *internet.TCPConn
state State
meterSerial string
mutex sync.Mutex
}
func NewMeter(socket *internet.TCPConn) *Meter {
return &Meter{
socket: socket,
state: Linked,
}
}
func (m *Meter) Learn() {
for {
information := make([]byte, 1024)
m.mutex.Lock()
n, err := m.socket.Learn(information)
m.mutex.Unlock()
if err == internet.ErrClosed {
m.socket.Shut()
return
}
if n > 0 {
hexString := hex.EncodeToString(information[:n])
fmt.Printf("Learn %d bytesnData: %sn", n, hexString)
m.OnData(hexString)
}
}
}
func (m *Meter) OnData(hexString string) {
if hexString == Handshake {
if m.state == Linked {
response, err := hex.DecodeString(AARE)
if err != nil {
fmt.Println(err)
}
go m.socket.Write(response)
m.state = ReadAARQ
return
} else {
response, err := hex.DecodeString(Handshake)
if err != nil {
fmt.Println(err)
}
go m.socket.Write(response)
return
}
}
if m.state == ReadAARQ {
if hexString == AARQ {
response, err := hex.DecodeString(GetSerialRequest)
if err != nil {
fmt.Println(err)
}
go m.socket.Write(response)
m.state = ReadSerial
return
}
}
if m.state == ReadSerial {
m.meterSerial = parseSerial(hexString)
from := time.Date(2023, 1, 1, 0, 0, 0, 0, time.Native)
m.getDailyBilling(from, time.Now())
return
}
if m.state == ReadDailyBilling {
parseDailyBilling(hexString)
if hexString[18:20] == "02" && hexString[22:24] != "01" {
response, _ := hex.DecodeString(fmt.Sprintf("0001001100010007c002c1percents", hexString[24:32]))
go m.socket.Write(response)
return
}
m.state = Idle
}
}
func parseSerial(hexData string) string {
if !strings.HasPrefix(hexData, "0001000100110012c401c100090c") {
return ""
}
bytes, err := hex.DecodeString(hexData[28:])
if err != nil {
fmt.Println(err)
}
return string(bytes)
}
func (m *Meter) getDailyBilling(dates ...time.Time) {
var from, to time.Time
if len(dates) > 2 || len(dates) == 0 {
return
}
if len(dates) == 1 {
from = dates[0]
to = dates[0].AddDate(0, 0, 1)
}
if len(dates) == 2 {
from = dates[0]
to = dates[1]
}
response, err := hex.DecodeString(fmt.Sprintf("0001001100010040c001c100070000620200ff0201010204020412000809060000010000ff0f02120000090cpercents090cpercents0100", dateToHex(from), dateToHex(to)))
if err != nil {
fmt.Println(err)
}
go m.socket.Write(response)
m.state = ReadDailyBilling
}
func parseDailyBilling(hexData string) []map[string]interface{} {
information := strings.Cut up(hexData, "0216090c")
if len(information) == 0 {
return nil
}
end result := make([]map[string]interface{}, 0)
for _, dailyData := vary information[1:] {
legitimate := true
if !strings.HasPrefix(dailyData, "07") {
legitimate = false
}
date := dlmsHexToDate(dailyData[0:24])
vals := regexp.MustCompile(".{1,10}").FindAllString(dailyData[24:234], -1)
studying := make([]int, 0)
for _, val := vary vals {
if !strings.HasPrefix(val, "06") {
legitimate = false
}
decVal, _ := hex.DecodeString(val[2:])
studying = append(studying, int(decVal[0]))
}
if !legitimate {
fmt.Println("complete buff:", information)
fmt.Println("date:", dailyData[0:24])
fmt.Println("vals:", vals)
panic("Bleeeee")
}
if legitimate {
end result = append(end result, map[string]interface{}{
"date": date,
"studying": studying,
})
}
}
return end result
}
func dateToHex(date time.Time) string {
return fmt.Sprintf("0percent02xpercent02xpercent02xpercent02xpercent02xpercent02xpercent02xFFFED400", date.12 months(), int(date.Month()), date.Day(), int(date.Weekday()), date.Hour(), date.Minute(), date.Second())
}
func dlmsHexToDate(hexString string) time.Time {
hexyear, _ := hex.DecodeString(hexString[0:4])
hexmonth, _ := hex.DecodeString(hexString[4:6])
hexday, _ := hex.DecodeString(hexString[6:8])
hexhour, _ := hex.DecodeString(hexString[10:12])
hexminute, _ := hex.DecodeString(hexString[12:14])
hexsecond, _ := hex.DecodeString(hexString[14:16])
yr, _ := strconv.ParseInt(string(hexyear), 0, 16)
month, _ := strconv.ParseInt(string(hexmonth), 0, 16)
day, _ := strconv.ParseInt(string(hexday), 0, 16)
hour, _ := strconv.ParseInt(string(hexhour), 0, 16)
minute, _ := strconv.ParseInt(string(hexminute), 0, 16)
second, _ := strconv.ParseInt(string(hexsecond), 0, 16)
return time.Date(int(yr), time.Month(month), int(day), int(hour), int(minute), int(second), 0, time.UTC)
}