package stats import ( "encoding/json" "fmt" "strconv" "strings" "lingniu-vehicle-ingest/go/vehicle-gateway/internal/envelope" ) const ( gb32960FuelCellEngineWorkMode = 2 yutongFuelCellRunningMode = 4 yutongFuelCellDrivingMode = 11 ) // PureHydrogenModeFromEnvelope returns whether the reported vehicle is in a // fuel-cell-only work mode and whether the source value is understood. // // The 32960 fuel-cell extension reports engine_work_state; production frames // use mode 2 for normal fuel-cell operation. Yutong reports the equivalent // state through TRIANGLE_STATE; production frames use 1 for inactive and 4/11 // for active fuel-cell operating modes. func PureHydrogenModeFromEnvelope(env envelope.FrameEnvelope) (active bool, known bool) { value, exists := env.Fields[envelope.FieldFuelCellWorkMode] if !exists { return false, false } mode, ok := integerMode(value) if !ok { return false, false } switch env.Protocol { case envelope.ProtocolGB32960: switch mode { case gb32960FuelCellEngineWorkMode: return true, true case 0, 1: return false, true default: return false, false } case envelope.ProtocolYutongMQTT: switch mode { case yutongFuelCellRunningMode, yutongFuelCellDrivingMode: return true, true case 1: return false, true default: return false, false } default: return false, false } } // PureHydrogenMileageDelta returns the odometer delta that can be attributed // to pure-hydrogen operation. Both endpoints must report a known active mode; // this deliberately leaves transitions and missing mode data unclassified. func PureHydrogenMileageDelta( previousKM float64, currentKM float64, previousActive bool, previousKnown bool, currentActive bool, currentKnown bool, ) float64 { delta := currentKM - previousKM if !previousKnown || !previousActive || !currentKnown || !currentActive { return 0 } if delta < 0 || delta > maxSelectedDailyMileageKM { return 0 } return delta } func integerMode(value any) (int, bool) { switch typed := value.(type) { case json.Number: parsed, err := strconv.Atoi(typed.String()) return parsed, err == nil case string: parsed, err := strconv.Atoi(strings.TrimSpace(typed)) return parsed, err == nil case int: return typed, true case int8: return int(typed), true case int16: return int(typed), true case int32: return int(typed), true case int64: return int(typed), true case uint: return int(typed), true case uint8: return int(typed), true case uint16: return int(typed), true case uint32: return int(typed), true case uint64: if typed > uint64(^uint(0)>>1) { return 0, false } return int(typed), true case float32: parsed := int(typed) return parsed, float32(parsed) == typed case float64: parsed := int(typed) return parsed, float64(parsed) == typed default: parsed, err := strconv.Atoi(strings.TrimSpace(fmt.Sprint(value))) return parsed, err == nil } }