func NewModbusFromConfig(other map[string]interface{}) (api.Meter, error) {
	cc := struct {
		Model              string
		modbus.Settings    `mapstructure:",squash"`
		Power, Energy, SoC string
		Timeout            time.Duration
	}{
		Power: "Power",
		Settings: modbus.Settings{
			ID: 1,
		},
	}

	if err := util.DecodeOther(other, &cc); err != nil {
		return nil, err
	}

	// assume RTU if not set and this is a known RS485 meter model
	if cc.RTU == nil {
		b := modbus.IsRS485(cc.Model)
		cc.RTU = &b
	}

	log := util.NewLogger("modbus")

	conn, err := modbus.NewConnection(cc.URI, cc.Device, cc.Comset, cc.Baudrate, *cc.RTU, cc.ID)
	if err != nil {
		return nil, err
	}

	// set non-default timeout
	if cc.Timeout > 0 {
		conn.Timeout(cc.Timeout)
	}

	conn.Logger(log.TRACE)

	// prepare device
	device, err := modbus.NewDevice(cc.Model, cc.SubDevice)

	if err == nil {
		err = device.Initialize(conn)

		// silence Kostal implementation errors
		if errors.Is(err, meters.ErrPartiallyOpened) {
			err = nil
		}
	}

	if err != nil {
		return nil, err
	}

	m := &Modbus{
		log:    log,
		conn:   conn,
		device: device,
	}

	cc.Power = modbus.ReadingName(cc.Power)
	if err := modbus.ParseOperation(device, cc.Power, &m.opPower); err != nil {
		return nil, fmt.Errorf("invalid measurement for power: %s", cc.Power)
	}

	// decorate energy reading
	var totalEnergy func() (float64, error)
	if cc.Energy != "" {
		cc.Energy = modbus.ReadingName(cc.Energy)
		if err := modbus.ParseOperation(device, cc.Energy, &m.opEnergy); err != nil {
			return nil, fmt.Errorf("invalid measurement for energy: %s", cc.Energy)
		}

		totalEnergy = m.totalEnergy
	}

	// decorate energy reading
	var soc func() (float64, error)
	if cc.SoC != "" {
		cc.SoC = modbus.ReadingName(cc.SoC)
		if err := modbus.ParseOperation(device, cc.SoC, &m.opSoC); err != nil {
			return nil, fmt.Errorf("invalid measurement for soc: %s", cc.SoC)
		}

		soc = m.soc
	}

	return decorateModbus(m, totalEnergy, soc), nil
}
// NewModbusFromConfig creates api.Meter from config
NewModbusFromConfig creates api.Meter from config
// NewModbusFromConfig creates api . Meter from config
func NewModbusFromConfig(other map[string]interface{}) (api.Meter, error) {
	cc := struct {
		Model              string
		modbus.Settings    `mapstructure:",squash"`
		Power, Energy, SoC string
		Timeout            time.Duration
	}{
		Power: "Power",
		Settings: modbus.Settings{
			ID: 1,
		},
	}
	if err := util.DecodeOther(other, &cc); err != nil {
		return nil, err
	}
	if cc.RTU == nil {
		b := modbus.IsRS485(cc.Model)
		cc.RTU = &b
	}
	log := util.NewLogger("modbus")
	conn, err := modbus.NewConnection(cc.URI, cc.Device, cc.Comset, cc.Baudrate, *cc.RTU, cc.ID)
	if err != nil {
		return nil, err
	}
	if cc.Timeout > 0 {
		conn.Timeout(cc.Timeout)
	}
	conn.Logger(log.TRACE)
	device, err := modbus.NewDevice(cc.Model, cc.SubDevice)
	if err == nil {
		err = device.Initialize(conn)
		if errors.Is(err, meters.ErrPartiallyOpened) {
			err = nil
		}
	}
	if err != nil {
		return nil, err
	}
	m := &Modbus{
		log:    log,
		conn:   conn,
		device: device,
	}
	cc.Power = modbus.ReadingName(cc.Power)
	if err := modbus.ParseOperation(device, cc.Power, &m.opPower); err != nil {
		return nil, fmt.Errorf("invalid measurement for power: %s", cc.Power)
	}
	var totalEnergy func() (float64, error)
	if cc.Energy != "" {
		cc.Energy = modbus.ReadingName(cc.Energy)
		if err := modbus.ParseOperation(device, cc.Energy, &m.opEnergy); err != nil {
			return nil, fmt.Errorf("invalid measurement for energy: %s", cc.Energy)
		}
		totalEnergy = m.totalEnergy
	}
	var soc func() (float64, error)
	if cc.SoC != "" {
		cc.SoC = modbus.ReadingName(cc.SoC)
		if err := modbus.ParseOperation(device, cc.SoC, &m.opSoC); err != nil {
			return nil, fmt.Errorf("invalid measurement for soc: %s", cc.SoC)
		}
		soc = m.soc
	}
	return decorateModbus(m, totalEnergy, soc), nil
}
func NewModbusFromConfig ( other map [ string ] interface { } ) ( api . Meter , error ) { cc := struct { Model string modbus . Settings `mapstructure:",squash"` Power , Energy , SoC string Timeout time . Duration } { Power : " " , Settings : modbus . Settings { ID : 1 , } , } if err := util . DecodeOther ( other , & cc ) ; err != nil { return nil , err } if cc . RTU == nil { b := modbus . IsRS485 ( cc . Model ) cc . RTU = & b } log := util . NewLogger ( " " ) conn , err := modbus . NewConnection ( cc . URI , cc . Device , cc . Comset , cc . Baudrate , * cc . RTU , cc . ID ) if err != nil { return nil , err } if cc . Timeout > 0 { conn . Timeout ( cc . Timeout ) } conn . Logger ( log . TRACE ) device , err := modbus . NewDevice ( cc . Model , cc . SubDevice ) if err == nil { err = device . Initialize ( conn ) if errors . Is ( err , meters . ErrPartiallyOpened ) { err = nil } } if err != nil { return nil , err } m := & Modbus { log : log , conn : conn , device : device , } cc . Power = modbus . ReadingName ( cc . Power ) if err := modbus . ParseOperation ( device , cc . Power , & m . opPower ) ; err != nil { return nil , fmt . Errorf ( " " , cc . Power ) } var totalEnergy func ( ) ( float64 , error ) if cc . Energy != " " { cc . Energy = modbus . ReadingName ( cc . Energy ) if err := modbus . ParseOperation ( device , cc . Energy , & m . opEnergy ) ; err != nil { return nil , fmt . Errorf ( " " , cc . Energy ) } totalEnergy = m . totalEnergy } var soc func ( ) ( float64 , error ) if cc . SoC != " " { cc . SoC = modbus . ReadingName ( cc . SoC ) if err := modbus . ParseOperation ( device , cc . SoC , & m . opSoC ) ; err != nil { return nil , fmt . Errorf ( " " , cc . SoC ) } soc = m . soc } return decorateModbus ( m , totalEnergy , soc ) , nil }
NewModbusFromConfig creates api.Meter from config
NewModbusFromConfig creates api . Meter from config
// assume RTU if not set and this is a known RS485 meter model // set non-default timeout // prepare device // silence Kostal implementation errors // decorate energy reading // decorate energy reading