package m31 import ( "bytes" "encoding/json" "math" "math/big" "time" "onehouse/driver" ) type outputRequest struct { command driver.Command point point analog bool value uint16 } func newOutputRequest(command driver.Command, topology topology, deviceID string, batch bool) (outputRequest, string) { request := outputRequest{command: command} if command.DeviceID != deviceID { return request, "Command belongs to another device" } if command.Expired(time.Now()) { return request, "Command expired" } value := bytes.TrimSpace(command.Payload.Value) for _, output := range topology.outputs { if output.id != command.Capability { continue } request.point = output if !bytes.Equal(value, []byte("true")) && !bytes.Equal(value, []byte("false")) { return request, "Digital output requires a Boolean value" } if bytes.Equal(value, []byte("true")) { request.value = 1 } if output.pulse != 0 && request.value != 1 { return request, "Pulse output requires true" } if batch && output.pulse != 0 { return request, "Batches require steady digital outputs" } return request, "" } for _, output := range topology.analog { if output.id != command.Capability { continue } request.point, request.analog = output, true if batch { return request, "Batches require steady digital outputs" } if len(value) == 0 || !json.Valid(value) || value[0] != '-' && (value[0] < '0' || value[0] > '9') { return request, "Analog output requires zero through ten volts" } number, valid := new(big.Rat).SetString(string(value)) if !valid || number.Sign() < 0 || number.Cmp(big.NewRat(10, 1)) > 0 { return request, "Analog output requires zero through ten volts" } voltage, _ := number.Float64() request.value = uint16(math.Round(voltage * 1000)) return request, "" } return request, "Capability is not a configured output" }