From c37420a9939a0a0bd78a9778dc6fa6425abcf2e2 Mon Sep 17 00:00:00 2001 From: Wolfgang Hottgenroth Date: Fri, 6 Mar 2026 20:51:50 +0100 Subject: [PATCH] float fix 1 --- .../instances/udi-influx/default/config.json | 1 + src/udi/handlers/sver/sver.go | 335 +++++++++--------- 2 files changed, 176 insertions(+), 160 deletions(-) diff --git a/deployment/instances/udi-influx/default/config.json b/deployment/instances/udi-influx/default/config.json index d774402..a0008b2 100644 --- a/deployment/instances/udi-influx/default/config.json +++ b/deployment/instances/udi-influx/default/config.json @@ -105,6 +105,7 @@ "devicePart": "3", "valueFrom": "payload", "valuePart": "1", + "valueType": "float", "unitFrom": "payload", "unitPart": "3" } diff --git a/src/udi/handlers/sver/sver.go b/src/udi/handlers/sver/sver.go index 5118a6b..aba6b60 100644 --- a/src/udi/handlers/sver/sver.go +++ b/src/udi/handlers/sver/sver.go @@ -1,23 +1,22 @@ package sver import ( - "time" - "strconv" - "strings" - "regexp" - "log" - "udi/config" - "udi/handlers/handler" - "udi/database" + "log" + "regexp" + "strconv" + "strings" + "time" + "udi/config" + "udi/database" + "udi/handlers/handler" ) - type SingleValueExtractorRegexHandler struct { - handler.CommonHandler - ready bool - config localConfig - payloadRegex *regexp.Regexp - dbh *database.DatabaseHandle + handler.CommonHandler + ready bool + config localConfig + payloadRegex *regexp.Regexp + dbh *database.DatabaseHandle } const TOPIC_SEL = "topic" @@ -26,175 +25,191 @@ const PAYLOAD_FULL_SEL = "payload-full" const CONSTANT_SEL = "constant" type localConfig struct { - application string - deviceFrom string - devicePart int - device string - valueFrom string - valuePart int - unitFrom string - unitPart int - unit string + application string + deviceFrom string + devicePart int + device string + valueFrom string + valuePart int + valueType string + unitFrom string + unitPart int + unit string } - func New(id string, config config.HandlerConfigT) handler.Handler { - t := &SingleValueExtractorRegexHandler { - ready: false, - } + t := &SingleValueExtractorRegexHandler{ + ready: false, + } - var localConfig localConfig - if config.Attributes["application"] == "" { - log.Println("Error: application not configured") - return t - } - localConfig.application = config.Attributes["application"] - - payloadRegex := config.Attributes["payloadRegex"] - if payloadRegex != "" { - t.payloadRegex = regexp.MustCompile(payloadRegex) - } else { - t.payloadRegex = nil - } + var localConfig localConfig + if config.Attributes["application"] == "" { + log.Println("Error: application not configured") + return t + } + localConfig.application = config.Attributes["application"] - if config.Attributes["deviceFrom"] != TOPIC_SEL && config.Attributes["deviceFrom"] != PAYLOAD_SEL && config.Attributes["deviceFrom"] != CONSTANT_SEL { - log.Printf("Error: invalid value %s for deviceFrom", config.Attributes["deviceFrom"]) - return t - } - localConfig.deviceFrom = config.Attributes["deviceFrom"] + payloadRegex := config.Attributes["payloadRegex"] + if payloadRegex != "" { + t.payloadRegex = regexp.MustCompile(payloadRegex) + } else { + t.payloadRegex = nil + } - devicePart, err1 := strconv.Atoi(config.Attributes["devicePart"]) - if err1 != nil { - log.Printf("Error: unable to convert devicePart to number: %s", err1) - return t - } - localConfig.devicePart = devicePart + if config.Attributes["deviceFrom"] != TOPIC_SEL && config.Attributes["deviceFrom"] != PAYLOAD_SEL && config.Attributes["deviceFrom"] != CONSTANT_SEL { + log.Printf("Error: invalid value %s for deviceFrom", config.Attributes["deviceFrom"]) + return t + } + localConfig.deviceFrom = config.Attributes["deviceFrom"] - // empty device is valid - localConfig.device = config.Attributes["device"] + devicePart, err1 := strconv.Atoi(config.Attributes["devicePart"]) + if err1 != nil { + log.Printf("Error: unable to convert devicePart to number: %s", err1) + return t + } + localConfig.devicePart = devicePart - if config.Attributes["valueFrom"] != PAYLOAD_SEL && config.Attributes["valueFrom"] != PAYLOAD_FULL_SEL { - log.Printf("Error: invalid value %s for valueFrom", config.Attributes["valueFrom"]) - return t - } - localConfig.valueFrom = config.Attributes["valueFrom"] + // empty device is valid + localConfig.device = config.Attributes["device"] - if config.Attributes["valueFrom"] == PAYLOAD_SEL { - valuePart, err2 := strconv.Atoi(config.Attributes["valuePart"]) - if err2 != nil { - log.Printf("Error: unable to convert valuePart to number: %s", err2) - return t - } - localConfig.valuePart = valuePart - } + if config.Attributes["valueFrom"] != PAYLOAD_SEL && config.Attributes["valueFrom"] != PAYLOAD_FULL_SEL { + log.Printf("Error: invalid value %s for valueFrom", config.Attributes["valueFrom"]) + return t + } + localConfig.valueFrom = config.Attributes["valueFrom"] - if config.Attributes["unitFrom"] != PAYLOAD_SEL && config.Attributes["unitFrom"] != CONSTANT_SEL { - log.Printf("Error: invalid value %s for unitFrom", config.Attributes["unitFrom"]) - return t - } - localConfig.unitFrom = config.Attributes["unitFrom"] + if config.Attributes["valueFrom"] == PAYLOAD_SEL { + valuePart, err2 := strconv.Atoi(config.Attributes["valuePart"]) + if err2 != nil { + log.Printf("Error: unable to convert valuePart to number: %s", err2) + return t + } + localConfig.valuePart = valuePart + } - if config.Attributes["unitFrom"] == PAYLOAD_SEL { - unitPart, err3 := strconv.Atoi(config.Attributes["unitPart"]) - if err3 != nil { - log.Printf("Error: unable to convert unitPart to number: %s", err3) - return t - } - localConfig.unitPart = unitPart - } + if config.Attributes["valueType"] != "float" && config.Attributes["valueType"] != "string" { + log.Printf("Error: invalid value %s for valueType", config.Attributes["valueType"]) + return t + } + localConfig.valueType = config.Attributes["valueType"] - // empty unit is valid - localConfig.unit = config.Attributes["unit"] + if config.Attributes["unitFrom"] != PAYLOAD_SEL && config.Attributes["unitFrom"] != CONSTANT_SEL { + log.Printf("Error: invalid value %s for unitFrom", config.Attributes["unitFrom"]) + return t + } + localConfig.unitFrom = config.Attributes["unitFrom"] - t.config = localConfig + if config.Attributes["unitFrom"] == PAYLOAD_SEL { + unitPart, err3 := strconv.Atoi(config.Attributes["unitPart"]) + if err3 != nil { + log.Printf("Error: unable to convert unitPart to number: %s", err3) + return t + } + localConfig.unitPart = unitPart + } - t.Id = id - t.ready = true - t.dbh = database.NewDatabaseHandle() - log.Printf("Handler SVER %d initialized", id) - return t + // empty unit is valid + localConfig.unit = config.Attributes["unit"] + + t.config = localConfig + + t.Id = id + t.ready = true + t.dbh = database.NewDatabaseHandle() + log.Printf("Handler SVER %d initialized", id) + return t } func (self *SingleValueExtractorRegexHandler) Handle(message handler.MessageT) { - if ! self.ready { - self.Lost("Handler is not marked as ready", nil, message) - return - } - //log.Printf("Handler SingleValueExtractor %d processing %s -> %s", self.id, message.Topic, message.Payload) + if !self.ready { + self.Lost("Handler is not marked as ready", nil, message) + return + } + //log.Printf("Handler SingleValueExtractor %d processing %s -> %s", self.id, message.Topic, message.Payload) - var measurement database.Measurement - measurement.Time = time.Now() - measurement.Application = self.config.application - - subTopics := strings.Split(message.Topic, "/") - //log.Printf("Subtopics: %s", strings.Join(subTopics, ", ")) + var measurement database.Measurement + measurement.Time = time.Now() + measurement.Application = self.config.application - var payloadMatches []string - if self.payloadRegex != nil { - payloadMatches = self.payloadRegex.FindStringSubmatch(message.Payload) - //log.Printf("Matches: %s", strings.Join(payloadMatches, ", ")) - } + subTopics := strings.Split(message.Topic, "/") + //log.Printf("Subtopics: %s", strings.Join(subTopics, ", ")) - switch self.config.deviceFrom { - case TOPIC_SEL: - if self.config.devicePart >= len(subTopics) { - self.Lost("devicePart out of range", nil, message) - return - } - measurement.Device = subTopics[self.config.devicePart] - case PAYLOAD_SEL: - if self.payloadRegex == nil { - self.Lost("no payloadRegex defined, devicePart can't be used", nil, message) - return - } - if self.config.devicePart >= len(payloadMatches) { - self.Lost("devicePart out of range", nil, message) - return - } - measurement.Device = payloadMatches[self.config.devicePart] - case CONSTANT_SEL: - measurement.Device = self.config.device - } + var payloadMatches []string + if self.payloadRegex != nil { + payloadMatches = self.payloadRegex.FindStringSubmatch(message.Payload) + //log.Printf("Matches: %s", strings.Join(payloadMatches, ", ")) + } - measurement.Values = make(map[string]database.VariableType) - var variable database.VariableType - variable.Label = "" - variable.Variable = "" + switch self.config.deviceFrom { + case TOPIC_SEL: + if self.config.devicePart >= len(subTopics) { + self.Lost("devicePart out of range", nil, message) + return + } + measurement.Device = subTopics[self.config.devicePart] + case PAYLOAD_SEL: + if self.payloadRegex == nil { + self.Lost("no payloadRegex defined, devicePart can't be used", nil, message) + return + } + if self.config.devicePart >= len(payloadMatches) { + self.Lost("devicePart out of range", nil, message) + return + } + measurement.Device = payloadMatches[self.config.devicePart] + case CONSTANT_SEL: + measurement.Device = self.config.device + } - switch self.config.valueFrom { - case PAYLOAD_SEL: - if self.payloadRegex == nil { - self.Lost("no payloadRegex defined, valuePart can't be used", nil, message) - return - } - if self.config.valuePart >= len(payloadMatches) { - self.Lost("valuePart out of range", nil, message) - return - } - variable.Value = payloadMatches[self.config.valuePart] - case PAYLOAD_FULL_SEL: - variable.Value = message.Payload - } + measurement.Values = make(map[string]database.VariableType) + var variable database.VariableType + variable.Label = "" + variable.Variable = "" - switch self.config.unitFrom { - case PAYLOAD_SEL: - if self.payloadRegex == nil { - self.Lost("no payloadRegex defined, unitPart can't be used", nil, message) - return - } - if self.config.unitPart >= len(payloadMatches) { - self.Lost("unitPart out of range", nil, message) - return - } - variable.Unit = payloadMatches[self.config.unitPart] - case CONSTANT_SEL: - variable.Unit = self.config.unit - } + var value string + switch self.config.valueFrom { + case PAYLOAD_SEL: + if self.payloadRegex == nil { + self.Lost("no payloadRegex defined, valuePart can't be used", nil, message) + return + } + if self.config.valuePart >= len(payloadMatches) { + self.Lost("valuePart out of range", nil, message) + return + } + value = payloadMatches[self.config.valuePart] + case PAYLOAD_FULL_SEL: + value = message.Payload + } + if self.config.valueType == "float" { + fValue, err := strconv.ParseFloat(value, 64) + if err != nil { + self.Lost("Unable to convert value to float", err, message) + return + } + variable.Value = fValue + } else { + variable.Value = value + } - measurement.Values["Value"] = variable + switch self.config.unitFrom { + case PAYLOAD_SEL: + if self.payloadRegex == nil { + self.Lost("no payloadRegex defined, unitPart can't be used", nil, message) + return + } + if self.config.unitPart >= len(payloadMatches) { + self.Lost("unitPart out of range", nil, message) + return + } + variable.Unit = payloadMatches[self.config.unitPart] + case CONSTANT_SEL: + variable.Unit = self.config.unit + } - //log.Printf("Prepared measurement item: %s", measurement) - self.dbh.StoreMeasurement(&measurement) - self.S() + measurement.Values["Value"] = variable + + //log.Printf("Prepared measurement item: %s", measurement) + self.dbh.StoreMeasurement(&measurement) + self.S() } -