You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by sr...@apache.org on 2022/07/19 14:00:53 UTC

[plc4x] branch develop updated: feat(cbus): implemented measurement application

This is an automated email from the ASF dual-hosted git repository.

sruehl pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git


The following commit(s) were added to refs/heads/develop by this push:
     new 65f759585 feat(cbus): implemented measurement application
65f759585 is described below

commit 65f7595859e44371c7231984994990477fe8f82b
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Tue Jul 19 16:00:45 2022 +0200

    feat(cbus): implemented measurement application
---
 plc4go/protocols/cbus/readwrite/ParserHelper.go    |   2 +
 plc4go/protocols/cbus/readwrite/XmlParserHelper.go |   2 +
 .../cbus/readwrite/model/MeasurementCommandType.go | 121 ++++++
 .../model/MeasurementCommandTypeContainer.go       | 166 ++++++++
 .../cbus/readwrite/model/MeasurementData.go        | 245 +++++++++++
 .../model/MeasurementDataChannelMeasurementData.go | 374 +++++++++++++++++
 .../cbus/readwrite/model/MeasurementUnits.go       | 449 +++++++++++++++++++++
 .../protocols/cbus/readwrite/model/StaticHelper.go |  10 +
 .../java/cbus/readwrite/utils/StaticHelper.java    |  11 +
 .../src/main/resources/protocols/cbus/c-bus.mspec  |  72 ++++
 10 files changed, 1452 insertions(+)

diff --git a/plc4go/protocols/cbus/readwrite/ParserHelper.go b/plc4go/protocols/cbus/readwrite/ParserHelper.go
index 5588d7768..f842b4617 100644
--- a/plc4go/protocols/cbus/readwrite/ParserHelper.go
+++ b/plc4go/protocols/cbus/readwrite/ParserHelper.go
@@ -189,6 +189,8 @@ func (m CbusParserHelper) Parse(typeName string, arguments []string, io utils.Re
 		return model.CBusConstantsParse(io)
 	case "SerialInterfaceAddress":
 		return model.SerialInterfaceAddressParse(io)
+	case "MeasurementData":
+		return model.MeasurementDataParse(io)
 	case "HVACZoneList":
 		return model.HVACZoneListParse(io)
 	case "ZoneStatus":
diff --git a/plc4go/protocols/cbus/readwrite/XmlParserHelper.go b/plc4go/protocols/cbus/readwrite/XmlParserHelper.go
index ff9c5bad5..fe878ee0d 100644
--- a/plc4go/protocols/cbus/readwrite/XmlParserHelper.go
+++ b/plc4go/protocols/cbus/readwrite/XmlParserHelper.go
@@ -214,6 +214,8 @@ func (m CbusXmlParserHelper) Parse(typeName string, xmlString string, parserArgu
 		return model.CBusConstantsParse(utils.NewXmlReadBuffer(strings.NewReader(xmlString)))
 	case "SerialInterfaceAddress":
 		return model.SerialInterfaceAddressParse(utils.NewXmlReadBuffer(strings.NewReader(xmlString)))
+	case "MeasurementData":
+		return model.MeasurementDataParse(utils.NewXmlReadBuffer(strings.NewReader(xmlString)))
 	case "HVACZoneList":
 		return model.HVACZoneListParse(utils.NewXmlReadBuffer(strings.NewReader(xmlString)))
 	case "ZoneStatus":
diff --git a/plc4go/protocols/cbus/readwrite/model/MeasurementCommandType.go b/plc4go/protocols/cbus/readwrite/model/MeasurementCommandType.go
new file mode 100644
index 000000000..4dbf23f8a
--- /dev/null
+++ b/plc4go/protocols/cbus/readwrite/model/MeasurementCommandType.go
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package model
+
+import (
+	"github.com/apache/plc4x/plc4go/internal/spi/utils"
+	"github.com/pkg/errors"
+	"github.com/rs/zerolog/log"
+)
+
+// Code generated by code-generation. DO NOT EDIT.
+
+// MeasurementCommandType is an enum
+type MeasurementCommandType uint8
+
+type IMeasurementCommandType interface {
+	Serialize(writeBuffer utils.WriteBuffer) error
+}
+
+const (
+	MeasurementCommandType_MEASUREMENT_EVENT MeasurementCommandType = 0x00
+)
+
+var MeasurementCommandTypeValues []MeasurementCommandType
+
+func init() {
+	_ = errors.New
+	MeasurementCommandTypeValues = []MeasurementCommandType{
+		MeasurementCommandType_MEASUREMENT_EVENT,
+	}
+}
+
+func MeasurementCommandTypeByValue(value uint8) (enum MeasurementCommandType, ok bool) {
+	switch value {
+	case 0x00:
+		return MeasurementCommandType_MEASUREMENT_EVENT, true
+	}
+	return 0, false
+}
+
+func MeasurementCommandTypeByName(value string) (enum MeasurementCommandType, ok bool) {
+	switch value {
+	case "MEASUREMENT_EVENT":
+		return MeasurementCommandType_MEASUREMENT_EVENT, true
+	}
+	return 0, false
+}
+
+func MeasurementCommandTypeKnows(value uint8) bool {
+	for _, typeValue := range MeasurementCommandTypeValues {
+		if uint8(typeValue) == value {
+			return true
+		}
+	}
+	return false
+}
+
+func CastMeasurementCommandType(structType interface{}) MeasurementCommandType {
+	castFunc := func(typ interface{}) MeasurementCommandType {
+		if sMeasurementCommandType, ok := typ.(MeasurementCommandType); ok {
+			return sMeasurementCommandType
+		}
+		return 0
+	}
+	return castFunc(structType)
+}
+
+func (m MeasurementCommandType) GetLengthInBits() uint16 {
+	return 4
+}
+
+func (m MeasurementCommandType) GetLengthInBytes() uint16 {
+	return m.GetLengthInBits() / 8
+}
+
+func MeasurementCommandTypeParse(readBuffer utils.ReadBuffer) (MeasurementCommandType, error) {
+	val, err := readBuffer.ReadUint8("MeasurementCommandType", 4)
+	if err != nil {
+		return 0, errors.Wrap(err, "error reading MeasurementCommandType")
+	}
+	if enum, ok := MeasurementCommandTypeByValue(val); !ok {
+		log.Debug().Msgf("no value %x found for RequestType", val)
+		return MeasurementCommandType(val), nil
+	} else {
+		return enum, nil
+	}
+}
+
+func (e MeasurementCommandType) Serialize(writeBuffer utils.WriteBuffer) error {
+	return writeBuffer.WriteUint8("MeasurementCommandType", 4, uint8(e), utils.WithAdditionalStringRepresentation(e.PLC4XEnumName()))
+}
+
+// PLC4XEnumName returns the name that is used in code to identify this enum
+func (e MeasurementCommandType) PLC4XEnumName() string {
+	switch e {
+	case MeasurementCommandType_MEASUREMENT_EVENT:
+		return "MEASUREMENT_EVENT"
+	}
+	return ""
+}
+
+func (e MeasurementCommandType) String() string {
+	return e.PLC4XEnumName()
+}
diff --git a/plc4go/protocols/cbus/readwrite/model/MeasurementCommandTypeContainer.go b/plc4go/protocols/cbus/readwrite/model/MeasurementCommandTypeContainer.go
new file mode 100644
index 000000000..e648106ee
--- /dev/null
+++ b/plc4go/protocols/cbus/readwrite/model/MeasurementCommandTypeContainer.go
@@ -0,0 +1,166 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package model
+
+import (
+	"github.com/apache/plc4x/plc4go/internal/spi/utils"
+	"github.com/pkg/errors"
+	"github.com/rs/zerolog/log"
+)
+
+// Code generated by code-generation. DO NOT EDIT.
+
+// MeasurementCommandTypeContainer is an enum
+type MeasurementCommandTypeContainer uint8
+
+type IMeasurementCommandTypeContainer interface {
+	NumBytes() uint8
+	CommandType() MeasurementCommandType
+	Serialize(writeBuffer utils.WriteBuffer) error
+}
+
+const (
+	MeasurementCommandTypeContainer_MeasurementCommandChannelMeasurementData MeasurementCommandTypeContainer = 0x0E
+)
+
+var MeasurementCommandTypeContainerValues []MeasurementCommandTypeContainer
+
+func init() {
+	_ = errors.New
+	MeasurementCommandTypeContainerValues = []MeasurementCommandTypeContainer{
+		MeasurementCommandTypeContainer_MeasurementCommandChannelMeasurementData,
+	}
+}
+
+func (e MeasurementCommandTypeContainer) NumBytes() uint8 {
+	switch e {
+	case 0x0E:
+		{ /* '0x0E' */
+			return 6
+		}
+	default:
+		{
+			return 0
+		}
+	}
+}
+
+func MeasurementCommandTypeContainerFirstEnumForFieldNumBytes(value uint8) (MeasurementCommandTypeContainer, error) {
+	for _, sizeValue := range MeasurementCommandTypeContainerValues {
+		if sizeValue.NumBytes() == value {
+			return sizeValue, nil
+		}
+	}
+	return 0, errors.Errorf("enum for %v describing NumBytes not found", value)
+}
+
+func (e MeasurementCommandTypeContainer) CommandType() MeasurementCommandType {
+	switch e {
+	case 0x0E:
+		{ /* '0x0E' */
+			return MeasurementCommandType_MEASUREMENT_EVENT
+		}
+	default:
+		{
+			return 0
+		}
+	}
+}
+
+func MeasurementCommandTypeContainerFirstEnumForFieldCommandType(value MeasurementCommandType) (MeasurementCommandTypeContainer, error) {
+	for _, sizeValue := range MeasurementCommandTypeContainerValues {
+		if sizeValue.CommandType() == value {
+			return sizeValue, nil
+		}
+	}
+	return 0, errors.Errorf("enum for %v describing CommandType not found", value)
+}
+func MeasurementCommandTypeContainerByValue(value uint8) (enum MeasurementCommandTypeContainer, ok bool) {
+	switch value {
+	case 0x0E:
+		return MeasurementCommandTypeContainer_MeasurementCommandChannelMeasurementData, true
+	}
+	return 0, false
+}
+
+func MeasurementCommandTypeContainerByName(value string) (enum MeasurementCommandTypeContainer, ok bool) {
+	switch value {
+	case "MeasurementCommandChannelMeasurementData":
+		return MeasurementCommandTypeContainer_MeasurementCommandChannelMeasurementData, true
+	}
+	return 0, false
+}
+
+func MeasurementCommandTypeContainerKnows(value uint8) bool {
+	for _, typeValue := range MeasurementCommandTypeContainerValues {
+		if uint8(typeValue) == value {
+			return true
+		}
+	}
+	return false
+}
+
+func CastMeasurementCommandTypeContainer(structType interface{}) MeasurementCommandTypeContainer {
+	castFunc := func(typ interface{}) MeasurementCommandTypeContainer {
+		if sMeasurementCommandTypeContainer, ok := typ.(MeasurementCommandTypeContainer); ok {
+			return sMeasurementCommandTypeContainer
+		}
+		return 0
+	}
+	return castFunc(structType)
+}
+
+func (m MeasurementCommandTypeContainer) GetLengthInBits() uint16 {
+	return 8
+}
+
+func (m MeasurementCommandTypeContainer) GetLengthInBytes() uint16 {
+	return m.GetLengthInBits() / 8
+}
+
+func MeasurementCommandTypeContainerParse(readBuffer utils.ReadBuffer) (MeasurementCommandTypeContainer, error) {
+	val, err := readBuffer.ReadUint8("MeasurementCommandTypeContainer", 8)
+	if err != nil {
+		return 0, errors.Wrap(err, "error reading MeasurementCommandTypeContainer")
+	}
+	if enum, ok := MeasurementCommandTypeContainerByValue(val); !ok {
+		log.Debug().Msgf("no value %x found for RequestType", val)
+		return MeasurementCommandTypeContainer(val), nil
+	} else {
+		return enum, nil
+	}
+}
+
+func (e MeasurementCommandTypeContainer) Serialize(writeBuffer utils.WriteBuffer) error {
+	return writeBuffer.WriteUint8("MeasurementCommandTypeContainer", 8, uint8(e), utils.WithAdditionalStringRepresentation(e.PLC4XEnumName()))
+}
+
+// PLC4XEnumName returns the name that is used in code to identify this enum
+func (e MeasurementCommandTypeContainer) PLC4XEnumName() string {
+	switch e {
+	case MeasurementCommandTypeContainer_MeasurementCommandChannelMeasurementData:
+		return "MeasurementCommandChannelMeasurementData"
+	}
+	return ""
+}
+
+func (e MeasurementCommandTypeContainer) String() string {
+	return e.PLC4XEnumName()
+}
diff --git a/plc4go/protocols/cbus/readwrite/model/MeasurementData.go b/plc4go/protocols/cbus/readwrite/model/MeasurementData.go
new file mode 100644
index 000000000..e8ea46879
--- /dev/null
+++ b/plc4go/protocols/cbus/readwrite/model/MeasurementData.go
@@ -0,0 +1,245 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package model
+
+import (
+	"github.com/apache/plc4x/plc4go/internal/spi/utils"
+	"github.com/pkg/errors"
+)
+
+// Code generated by code-generation. DO NOT EDIT.
+
+// MeasurementData is the corresponding interface of MeasurementData
+type MeasurementData interface {
+	utils.LengthAware
+	utils.Serializable
+	// GetCommandTypeContainer returns CommandTypeContainer (property field)
+	GetCommandTypeContainer() MeasurementCommandTypeContainer
+	// GetCommandType returns CommandType (virtual field)
+	GetCommandType() MeasurementCommandType
+}
+
+// MeasurementDataExactly can be used when we want exactly this type and not a type which fulfills MeasurementData.
+// This is useful for switch cases.
+type MeasurementDataExactly interface {
+	MeasurementData
+	isMeasurementData() bool
+}
+
+// _MeasurementData is the data-structure of this message
+type _MeasurementData struct {
+	_MeasurementDataChildRequirements
+	CommandTypeContainer MeasurementCommandTypeContainer
+}
+
+type _MeasurementDataChildRequirements interface {
+	utils.Serializable
+	GetLengthInBits() uint16
+	GetLengthInBitsConditional(lastItem bool) uint16
+}
+
+type MeasurementDataParent interface {
+	SerializeParent(writeBuffer utils.WriteBuffer, child MeasurementData, serializeChildFunction func() error) error
+	GetTypeName() string
+}
+
+type MeasurementDataChild interface {
+	utils.Serializable
+	InitializeParent(parent MeasurementData, commandTypeContainer MeasurementCommandTypeContainer)
+	GetParent() *MeasurementData
+
+	GetTypeName() string
+	MeasurementData
+}
+
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+/////////////////////// Accessors for property fields.
+///////////////////////
+
+func (m *_MeasurementData) GetCommandTypeContainer() MeasurementCommandTypeContainer {
+	return m.CommandTypeContainer
+}
+
+///////////////////////
+///////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+/////////////////////// Accessors for virtual fields.
+///////////////////////
+
+func (m *_MeasurementData) GetCommandType() MeasurementCommandType {
+	return CastMeasurementCommandType(m.GetCommandTypeContainer().CommandType())
+}
+
+///////////////////////
+///////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+
+// NewMeasurementData factory function for _MeasurementData
+func NewMeasurementData(commandTypeContainer MeasurementCommandTypeContainer) *_MeasurementData {
+	return &_MeasurementData{CommandTypeContainer: commandTypeContainer}
+}
+
+// Deprecated: use the interface for direct cast
+func CastMeasurementData(structType interface{}) MeasurementData {
+	if casted, ok := structType.(MeasurementData); ok {
+		return casted
+	}
+	if casted, ok := structType.(*MeasurementData); ok {
+		return *casted
+	}
+	return nil
+}
+
+func (m *_MeasurementData) GetTypeName() string {
+	return "MeasurementData"
+}
+
+func (m *_MeasurementData) GetParentLengthInBits() uint16 {
+	lengthInBits := uint16(0)
+
+	// Simple field (commandTypeContainer)
+	lengthInBits += 8
+
+	// A virtual field doesn't have any in- or output.
+
+	return lengthInBits
+}
+
+func (m *_MeasurementData) GetLengthInBytes() uint16 {
+	return m.GetLengthInBits() / 8
+}
+
+func MeasurementDataParse(readBuffer utils.ReadBuffer) (MeasurementData, error) {
+	positionAware := readBuffer
+	_ = positionAware
+	if pullErr := readBuffer.PullContext("MeasurementData"); pullErr != nil {
+		return nil, errors.Wrap(pullErr, "Error pulling for MeasurementData")
+	}
+	currentPos := positionAware.GetPos()
+	_ = currentPos
+
+	// Validation
+	if !(KnowsMeasurementCommandTypeContainer(readBuffer)) {
+		return nil, errors.WithStack(utils.ParseAssertError{"no command type could be found"})
+	}
+
+	// Simple Field (commandTypeContainer)
+	if pullErr := readBuffer.PullContext("commandTypeContainer"); pullErr != nil {
+		return nil, errors.Wrap(pullErr, "Error pulling for commandTypeContainer")
+	}
+	_commandTypeContainer, _commandTypeContainerErr := MeasurementCommandTypeContainerParse(readBuffer)
+	if _commandTypeContainerErr != nil {
+		return nil, errors.Wrap(_commandTypeContainerErr, "Error parsing 'commandTypeContainer' field of MeasurementData")
+	}
+	commandTypeContainer := _commandTypeContainer
+	if closeErr := readBuffer.CloseContext("commandTypeContainer"); closeErr != nil {
+		return nil, errors.Wrap(closeErr, "Error closing for commandTypeContainer")
+	}
+
+	// Virtual field
+	_commandType := commandTypeContainer.CommandType()
+	commandType := MeasurementCommandType(_commandType)
+	_ = commandType
+
+	// Switch Field (Depending on the discriminator values, passes the instantiation to a sub-type)
+	type MeasurementDataChildSerializeRequirement interface {
+		MeasurementData
+		InitializeParent(MeasurementData, MeasurementCommandTypeContainer)
+		GetParent() MeasurementData
+	}
+	var _childTemp interface{}
+	var _child MeasurementDataChildSerializeRequirement
+	var typeSwitchError error
+	switch {
+	case commandType == MeasurementCommandType_MEASUREMENT_EVENT: // MeasurementDataChannelMeasurementData
+		_childTemp, typeSwitchError = MeasurementDataChannelMeasurementDataParse(readBuffer)
+	default:
+		typeSwitchError = errors.Errorf("Unmapped type for parameters [commandType=%v]", commandType)
+	}
+	if typeSwitchError != nil {
+		return nil, errors.Wrap(typeSwitchError, "Error parsing sub-type for type-switch of MeasurementData")
+	}
+	_child = _childTemp.(MeasurementDataChildSerializeRequirement)
+
+	if closeErr := readBuffer.CloseContext("MeasurementData"); closeErr != nil {
+		return nil, errors.Wrap(closeErr, "Error closing for MeasurementData")
+	}
+
+	// Finish initializing
+	_child.InitializeParent(_child, commandTypeContainer)
+	return _child, nil
+}
+
+func (pm *_MeasurementData) SerializeParent(writeBuffer utils.WriteBuffer, child MeasurementData, serializeChildFunction func() error) error {
+	// We redirect all calls through client as some methods are only implemented there
+	m := child
+	_ = m
+	positionAware := writeBuffer
+	_ = positionAware
+	if pushErr := writeBuffer.PushContext("MeasurementData"); pushErr != nil {
+		return errors.Wrap(pushErr, "Error pushing for MeasurementData")
+	}
+
+	// Simple Field (commandTypeContainer)
+	if pushErr := writeBuffer.PushContext("commandTypeContainer"); pushErr != nil {
+		return errors.Wrap(pushErr, "Error pushing for commandTypeContainer")
+	}
+	_commandTypeContainerErr := writeBuffer.WriteSerializable(m.GetCommandTypeContainer())
+	if popErr := writeBuffer.PopContext("commandTypeContainer"); popErr != nil {
+		return errors.Wrap(popErr, "Error popping for commandTypeContainer")
+	}
+	if _commandTypeContainerErr != nil {
+		return errors.Wrap(_commandTypeContainerErr, "Error serializing 'commandTypeContainer' field")
+	}
+	// Virtual field
+	if _commandTypeErr := writeBuffer.WriteVirtual("commandType", m.GetCommandType()); _commandTypeErr != nil {
+		return errors.Wrap(_commandTypeErr, "Error serializing 'commandType' field")
+	}
+
+	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
+	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
+		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
+	}
+
+	if popErr := writeBuffer.PopContext("MeasurementData"); popErr != nil {
+		return errors.Wrap(popErr, "Error popping for MeasurementData")
+	}
+	return nil
+}
+
+func (m *_MeasurementData) isMeasurementData() bool {
+	return true
+}
+
+func (m *_MeasurementData) String() string {
+	if m == nil {
+		return "<nil>"
+	}
+	writeBuffer := utils.NewBoxedWriteBufferWithOptions(true, true)
+	if err := writeBuffer.WriteSerializable(m); err != nil {
+		return err.Error()
+	}
+	return writeBuffer.GetBox().String()
+}
diff --git a/plc4go/protocols/cbus/readwrite/model/MeasurementDataChannelMeasurementData.go b/plc4go/protocols/cbus/readwrite/model/MeasurementDataChannelMeasurementData.go
new file mode 100644
index 000000000..d76919c82
--- /dev/null
+++ b/plc4go/protocols/cbus/readwrite/model/MeasurementDataChannelMeasurementData.go
@@ -0,0 +1,374 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package model
+
+import (
+	"github.com/apache/plc4x/plc4go/internal/spi/utils"
+	"github.com/pkg/errors"
+)
+
+// Code generated by code-generation. DO NOT EDIT.
+
+// MeasurementDataChannelMeasurementData is the corresponding interface of MeasurementDataChannelMeasurementData
+type MeasurementDataChannelMeasurementData interface {
+	utils.LengthAware
+	utils.Serializable
+	MeasurementData
+	// GetDeviceId returns DeviceId (property field)
+	GetDeviceId() uint8
+	// GetChannel returns Channel (property field)
+	GetChannel() uint8
+	// GetUnits returns Units (property field)
+	GetUnits() MeasurementUnits
+	// GetMultiplier returns Multiplier (property field)
+	GetMultiplier() int8
+	// GetMsb returns Msb (property field)
+	GetMsb() uint8
+	// GetLsb returns Lsb (property field)
+	GetLsb() uint8
+	// GetRawValue returns RawValue (virtual field)
+	GetRawValue() uint16
+	// GetValue returns Value (virtual field)
+	GetValue() float64
+}
+
+// MeasurementDataChannelMeasurementDataExactly can be used when we want exactly this type and not a type which fulfills MeasurementDataChannelMeasurementData.
+// This is useful for switch cases.
+type MeasurementDataChannelMeasurementDataExactly interface {
+	MeasurementDataChannelMeasurementData
+	isMeasurementDataChannelMeasurementData() bool
+}
+
+// _MeasurementDataChannelMeasurementData is the data-structure of this message
+type _MeasurementDataChannelMeasurementData struct {
+	*_MeasurementData
+	DeviceId   uint8
+	Channel    uint8
+	Units      MeasurementUnits
+	Multiplier int8
+	Msb        uint8
+	Lsb        uint8
+}
+
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+/////////////////////// Accessors for discriminator values.
+///////////////////////
+
+///////////////////////
+///////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+
+func (m *_MeasurementDataChannelMeasurementData) InitializeParent(parent MeasurementData, commandTypeContainer MeasurementCommandTypeContainer) {
+	m.CommandTypeContainer = commandTypeContainer
+}
+
+func (m *_MeasurementDataChannelMeasurementData) GetParent() MeasurementData {
+	return m._MeasurementData
+}
+
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+/////////////////////// Accessors for property fields.
+///////////////////////
+
+func (m *_MeasurementDataChannelMeasurementData) GetDeviceId() uint8 {
+	return m.DeviceId
+}
+
+func (m *_MeasurementDataChannelMeasurementData) GetChannel() uint8 {
+	return m.Channel
+}
+
+func (m *_MeasurementDataChannelMeasurementData) GetUnits() MeasurementUnits {
+	return m.Units
+}
+
+func (m *_MeasurementDataChannelMeasurementData) GetMultiplier() int8 {
+	return m.Multiplier
+}
+
+func (m *_MeasurementDataChannelMeasurementData) GetMsb() uint8 {
+	return m.Msb
+}
+
+func (m *_MeasurementDataChannelMeasurementData) GetLsb() uint8 {
+	return m.Lsb
+}
+
+///////////////////////
+///////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+/////////////////////// Accessors for virtual fields.
+///////////////////////
+
+func (m *_MeasurementDataChannelMeasurementData) GetRawValue() uint16 {
+	return uint16(uint16(uint16(m.GetMsb())<<uint16(uint16(8))) | uint16(m.GetLsb()))
+}
+
+func (m *_MeasurementDataChannelMeasurementData) GetValue() float64 {
+	return float64(float64(float64(m.GetRawValue())*float64(m.GetMultiplier())) * float64(float64(10)))
+}
+
+///////////////////////
+///////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+
+// NewMeasurementDataChannelMeasurementData factory function for _MeasurementDataChannelMeasurementData
+func NewMeasurementDataChannelMeasurementData(deviceId uint8, channel uint8, units MeasurementUnits, multiplier int8, msb uint8, lsb uint8, commandTypeContainer MeasurementCommandTypeContainer) *_MeasurementDataChannelMeasurementData {
+	_result := &_MeasurementDataChannelMeasurementData{
+		DeviceId:         deviceId,
+		Channel:          channel,
+		Units:            units,
+		Multiplier:       multiplier,
+		Msb:              msb,
+		Lsb:              lsb,
+		_MeasurementData: NewMeasurementData(commandTypeContainer),
+	}
+	_result._MeasurementData._MeasurementDataChildRequirements = _result
+	return _result
+}
+
+// Deprecated: use the interface for direct cast
+func CastMeasurementDataChannelMeasurementData(structType interface{}) MeasurementDataChannelMeasurementData {
+	if casted, ok := structType.(MeasurementDataChannelMeasurementData); ok {
+		return casted
+	}
+	if casted, ok := structType.(*MeasurementDataChannelMeasurementData); ok {
+		return *casted
+	}
+	return nil
+}
+
+func (m *_MeasurementDataChannelMeasurementData) GetTypeName() string {
+	return "MeasurementDataChannelMeasurementData"
+}
+
+func (m *_MeasurementDataChannelMeasurementData) GetLengthInBits() uint16 {
+	return m.GetLengthInBitsConditional(false)
+}
+
+func (m *_MeasurementDataChannelMeasurementData) GetLengthInBitsConditional(lastItem bool) uint16 {
+	lengthInBits := uint16(m.GetParentLengthInBits())
+
+	// Simple field (deviceId)
+	lengthInBits += 8
+
+	// Simple field (channel)
+	lengthInBits += 8
+
+	// Simple field (units)
+	lengthInBits += 8
+
+	// Simple field (multiplier)
+	lengthInBits += 8
+
+	// Simple field (msb)
+	lengthInBits += 8
+
+	// Simple field (lsb)
+	lengthInBits += 8
+
+	// A virtual field doesn't have any in- or output.
+
+	// A virtual field doesn't have any in- or output.
+
+	return lengthInBits
+}
+
+func (m *_MeasurementDataChannelMeasurementData) GetLengthInBytes() uint16 {
+	return m.GetLengthInBits() / 8
+}
+
+func MeasurementDataChannelMeasurementDataParse(readBuffer utils.ReadBuffer) (MeasurementDataChannelMeasurementData, error) {
+	positionAware := readBuffer
+	_ = positionAware
+	if pullErr := readBuffer.PullContext("MeasurementDataChannelMeasurementData"); pullErr != nil {
+		return nil, errors.Wrap(pullErr, "Error pulling for MeasurementDataChannelMeasurementData")
+	}
+	currentPos := positionAware.GetPos()
+	_ = currentPos
+
+	// Simple Field (deviceId)
+	_deviceId, _deviceIdErr := readBuffer.ReadUint8("deviceId", 8)
+	if _deviceIdErr != nil {
+		return nil, errors.Wrap(_deviceIdErr, "Error parsing 'deviceId' field of MeasurementDataChannelMeasurementData")
+	}
+	deviceId := _deviceId
+
+	// Simple Field (channel)
+	_channel, _channelErr := readBuffer.ReadUint8("channel", 8)
+	if _channelErr != nil {
+		return nil, errors.Wrap(_channelErr, "Error parsing 'channel' field of MeasurementDataChannelMeasurementData")
+	}
+	channel := _channel
+
+	// Simple Field (units)
+	if pullErr := readBuffer.PullContext("units"); pullErr != nil {
+		return nil, errors.Wrap(pullErr, "Error pulling for units")
+	}
+	_units, _unitsErr := MeasurementUnitsParse(readBuffer)
+	if _unitsErr != nil {
+		return nil, errors.Wrap(_unitsErr, "Error parsing 'units' field of MeasurementDataChannelMeasurementData")
+	}
+	units := _units
+	if closeErr := readBuffer.CloseContext("units"); closeErr != nil {
+		return nil, errors.Wrap(closeErr, "Error closing for units")
+	}
+
+	// Simple Field (multiplier)
+	_multiplier, _multiplierErr := readBuffer.ReadInt8("multiplier", 8)
+	if _multiplierErr != nil {
+		return nil, errors.Wrap(_multiplierErr, "Error parsing 'multiplier' field of MeasurementDataChannelMeasurementData")
+	}
+	multiplier := _multiplier
+
+	// Simple Field (msb)
+	_msb, _msbErr := readBuffer.ReadUint8("msb", 8)
+	if _msbErr != nil {
+		return nil, errors.Wrap(_msbErr, "Error parsing 'msb' field of MeasurementDataChannelMeasurementData")
+	}
+	msb := _msb
+
+	// Simple Field (lsb)
+	_lsb, _lsbErr := readBuffer.ReadUint8("lsb", 8)
+	if _lsbErr != nil {
+		return nil, errors.Wrap(_lsbErr, "Error parsing 'lsb' field of MeasurementDataChannelMeasurementData")
+	}
+	lsb := _lsb
+
+	// Virtual field
+	_rawValue := uint16(uint16(msb)<<uint16(uint16(8))) | uint16(lsb)
+	rawValue := uint16(_rawValue)
+	_ = rawValue
+
+	// Virtual field
+	_value := float64(float64(rawValue)*float64(multiplier)) * float64(float64(10))
+	value := float64(_value)
+	_ = value
+
+	if closeErr := readBuffer.CloseContext("MeasurementDataChannelMeasurementData"); closeErr != nil {
+		return nil, errors.Wrap(closeErr, "Error closing for MeasurementDataChannelMeasurementData")
+	}
+
+	// Create a partially initialized instance
+	_child := &_MeasurementDataChannelMeasurementData{
+		DeviceId:         deviceId,
+		Channel:          channel,
+		Units:            units,
+		Multiplier:       multiplier,
+		Msb:              msb,
+		Lsb:              lsb,
+		_MeasurementData: &_MeasurementData{},
+	}
+	_child._MeasurementData._MeasurementDataChildRequirements = _child
+	return _child, nil
+}
+
+func (m *_MeasurementDataChannelMeasurementData) Serialize(writeBuffer utils.WriteBuffer) error {
+	positionAware := writeBuffer
+	_ = positionAware
+	ser := func() error {
+		if pushErr := writeBuffer.PushContext("MeasurementDataChannelMeasurementData"); pushErr != nil {
+			return errors.Wrap(pushErr, "Error pushing for MeasurementDataChannelMeasurementData")
+		}
+
+		// Simple Field (deviceId)
+		deviceId := uint8(m.GetDeviceId())
+		_deviceIdErr := writeBuffer.WriteUint8("deviceId", 8, (deviceId))
+		if _deviceIdErr != nil {
+			return errors.Wrap(_deviceIdErr, "Error serializing 'deviceId' field")
+		}
+
+		// Simple Field (channel)
+		channel := uint8(m.GetChannel())
+		_channelErr := writeBuffer.WriteUint8("channel", 8, (channel))
+		if _channelErr != nil {
+			return errors.Wrap(_channelErr, "Error serializing 'channel' field")
+		}
+
+		// Simple Field (units)
+		if pushErr := writeBuffer.PushContext("units"); pushErr != nil {
+			return errors.Wrap(pushErr, "Error pushing for units")
+		}
+		_unitsErr := writeBuffer.WriteSerializable(m.GetUnits())
+		if popErr := writeBuffer.PopContext("units"); popErr != nil {
+			return errors.Wrap(popErr, "Error popping for units")
+		}
+		if _unitsErr != nil {
+			return errors.Wrap(_unitsErr, "Error serializing 'units' field")
+		}
+
+		// Simple Field (multiplier)
+		multiplier := int8(m.GetMultiplier())
+		_multiplierErr := writeBuffer.WriteInt8("multiplier", 8, (multiplier))
+		if _multiplierErr != nil {
+			return errors.Wrap(_multiplierErr, "Error serializing 'multiplier' field")
+		}
+
+		// Simple Field (msb)
+		msb := uint8(m.GetMsb())
+		_msbErr := writeBuffer.WriteUint8("msb", 8, (msb))
+		if _msbErr != nil {
+			return errors.Wrap(_msbErr, "Error serializing 'msb' field")
+		}
+
+		// Simple Field (lsb)
+		lsb := uint8(m.GetLsb())
+		_lsbErr := writeBuffer.WriteUint8("lsb", 8, (lsb))
+		if _lsbErr != nil {
+			return errors.Wrap(_lsbErr, "Error serializing 'lsb' field")
+		}
+		// Virtual field
+		if _rawValueErr := writeBuffer.WriteVirtual("rawValue", m.GetRawValue()); _rawValueErr != nil {
+			return errors.Wrap(_rawValueErr, "Error serializing 'rawValue' field")
+		}
+		// Virtual field
+		if _valueErr := writeBuffer.WriteVirtual("value", m.GetValue()); _valueErr != nil {
+			return errors.Wrap(_valueErr, "Error serializing 'value' field")
+		}
+
+		if popErr := writeBuffer.PopContext("MeasurementDataChannelMeasurementData"); popErr != nil {
+			return errors.Wrap(popErr, "Error popping for MeasurementDataChannelMeasurementData")
+		}
+		return nil
+	}
+	return m.SerializeParent(writeBuffer, m, ser)
+}
+
+func (m *_MeasurementDataChannelMeasurementData) isMeasurementDataChannelMeasurementData() bool {
+	return true
+}
+
+func (m *_MeasurementDataChannelMeasurementData) String() string {
+	if m == nil {
+		return "<nil>"
+	}
+	writeBuffer := utils.NewBoxedWriteBufferWithOptions(true, true)
+	if err := writeBuffer.WriteSerializable(m); err != nil {
+		return err.Error()
+	}
+	return writeBuffer.GetBox().String()
+}
diff --git a/plc4go/protocols/cbus/readwrite/model/MeasurementUnits.go b/plc4go/protocols/cbus/readwrite/model/MeasurementUnits.go
new file mode 100644
index 000000000..fd3ab95f1
--- /dev/null
+++ b/plc4go/protocols/cbus/readwrite/model/MeasurementUnits.go
@@ -0,0 +1,449 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package model
+
+import (
+	"github.com/apache/plc4x/plc4go/internal/spi/utils"
+	"github.com/pkg/errors"
+	"github.com/rs/zerolog/log"
+)
+
+// Code generated by code-generation. DO NOT EDIT.
+
+// MeasurementUnits is an enum
+type MeasurementUnits uint8
+
+type IMeasurementUnits interface {
+	Serialize(writeBuffer utils.WriteBuffer) error
+}
+
+const (
+	MeasurementUnits_CELSIUS              MeasurementUnits = 0x00
+	MeasurementUnits_AMPS                 MeasurementUnits = 0x01
+	MeasurementUnits_ANGLE_DEGREES        MeasurementUnits = 0x02
+	MeasurementUnits_COULOMB              MeasurementUnits = 0x03
+	MeasurementUnits_BOOLEANLOGIC         MeasurementUnits = 0x04
+	MeasurementUnits_FARADS               MeasurementUnits = 0x05
+	MeasurementUnits_HENRYS               MeasurementUnits = 0x06
+	MeasurementUnits_HERTZ                MeasurementUnits = 0x07
+	MeasurementUnits_JOULES               MeasurementUnits = 0x08
+	MeasurementUnits_KATAL                MeasurementUnits = 0x09
+	MeasurementUnits_KG_PER_M3            MeasurementUnits = 0x0A
+	MeasurementUnits_KILOGRAMS            MeasurementUnits = 0x0B
+	MeasurementUnits_LITRES               MeasurementUnits = 0x0C
+	MeasurementUnits_LITRES_PER_HOUR      MeasurementUnits = 0x0D
+	MeasurementUnits_LITRES_PER_MINUTE    MeasurementUnits = 0x0E
+	MeasurementUnits_LITRES_PER_SECOND    MeasurementUnits = 0x0F
+	MeasurementUnits_LUX                  MeasurementUnits = 0x10
+	MeasurementUnits_METRES               MeasurementUnits = 0x11
+	MeasurementUnits_METRES_PER_MINUTE    MeasurementUnits = 0x12
+	MeasurementUnits_METRES_PER_SECOND    MeasurementUnits = 0x13
+	MeasurementUnits_METRES_PER_S_SQUARED MeasurementUnits = 0x14
+	MeasurementUnits_MOLE                 MeasurementUnits = 0x15
+	MeasurementUnits_NEWTON_METRE         MeasurementUnits = 0x16
+	MeasurementUnits_NEWTONS              MeasurementUnits = 0x17
+	MeasurementUnits_OHMS                 MeasurementUnits = 0x18
+	MeasurementUnits_PASCAL               MeasurementUnits = 0x19
+	MeasurementUnits_PERCENT              MeasurementUnits = 0x1A
+	MeasurementUnits_DECIBELS             MeasurementUnits = 0x1B
+	MeasurementUnits_PPM                  MeasurementUnits = 0x1C
+	MeasurementUnits_RPM                  MeasurementUnits = 0x1D
+	MeasurementUnits_SECOND               MeasurementUnits = 0x1E
+	MeasurementUnits_MINUTES              MeasurementUnits = 0x1F
+	MeasurementUnits_HOURS                MeasurementUnits = 0x20
+	MeasurementUnits_SIEVERTS             MeasurementUnits = 0x21
+	MeasurementUnits_STERADIAN            MeasurementUnits = 0x22
+	MeasurementUnits_TESLA                MeasurementUnits = 0x23
+	MeasurementUnits_VOLTS                MeasurementUnits = 0x24
+	MeasurementUnits_WATT_HOURS           MeasurementUnits = 0x25
+	MeasurementUnits_WATTS                MeasurementUnits = 0x26
+	MeasurementUnits_WEBERS               MeasurementUnits = 0x27
+	MeasurementUnits_NO_UNITS             MeasurementUnits = 0xFE
+	MeasurementUnits_CUSTOM               MeasurementUnits = 0xFF
+)
+
+var MeasurementUnitsValues []MeasurementUnits
+
+func init() {
+	_ = errors.New
+	MeasurementUnitsValues = []MeasurementUnits{
+		MeasurementUnits_CELSIUS,
+		MeasurementUnits_AMPS,
+		MeasurementUnits_ANGLE_DEGREES,
+		MeasurementUnits_COULOMB,
+		MeasurementUnits_BOOLEANLOGIC,
+		MeasurementUnits_FARADS,
+		MeasurementUnits_HENRYS,
+		MeasurementUnits_HERTZ,
+		MeasurementUnits_JOULES,
+		MeasurementUnits_KATAL,
+		MeasurementUnits_KG_PER_M3,
+		MeasurementUnits_KILOGRAMS,
+		MeasurementUnits_LITRES,
+		MeasurementUnits_LITRES_PER_HOUR,
+		MeasurementUnits_LITRES_PER_MINUTE,
+		MeasurementUnits_LITRES_PER_SECOND,
+		MeasurementUnits_LUX,
+		MeasurementUnits_METRES,
+		MeasurementUnits_METRES_PER_MINUTE,
+		MeasurementUnits_METRES_PER_SECOND,
+		MeasurementUnits_METRES_PER_S_SQUARED,
+		MeasurementUnits_MOLE,
+		MeasurementUnits_NEWTON_METRE,
+		MeasurementUnits_NEWTONS,
+		MeasurementUnits_OHMS,
+		MeasurementUnits_PASCAL,
+		MeasurementUnits_PERCENT,
+		MeasurementUnits_DECIBELS,
+		MeasurementUnits_PPM,
+		MeasurementUnits_RPM,
+		MeasurementUnits_SECOND,
+		MeasurementUnits_MINUTES,
+		MeasurementUnits_HOURS,
+		MeasurementUnits_SIEVERTS,
+		MeasurementUnits_STERADIAN,
+		MeasurementUnits_TESLA,
+		MeasurementUnits_VOLTS,
+		MeasurementUnits_WATT_HOURS,
+		MeasurementUnits_WATTS,
+		MeasurementUnits_WEBERS,
+		MeasurementUnits_NO_UNITS,
+		MeasurementUnits_CUSTOM,
+	}
+}
+
+func MeasurementUnitsByValue(value uint8) (enum MeasurementUnits, ok bool) {
+	switch value {
+	case 0x00:
+		return MeasurementUnits_CELSIUS, true
+	case 0x01:
+		return MeasurementUnits_AMPS, true
+	case 0x02:
+		return MeasurementUnits_ANGLE_DEGREES, true
+	case 0x03:
+		return MeasurementUnits_COULOMB, true
+	case 0x04:
+		return MeasurementUnits_BOOLEANLOGIC, true
+	case 0x05:
+		return MeasurementUnits_FARADS, true
+	case 0x06:
+		return MeasurementUnits_HENRYS, true
+	case 0x07:
+		return MeasurementUnits_HERTZ, true
+	case 0x08:
+		return MeasurementUnits_JOULES, true
+	case 0x09:
+		return MeasurementUnits_KATAL, true
+	case 0x0A:
+		return MeasurementUnits_KG_PER_M3, true
+	case 0x0B:
+		return MeasurementUnits_KILOGRAMS, true
+	case 0x0C:
+		return MeasurementUnits_LITRES, true
+	case 0x0D:
+		return MeasurementUnits_LITRES_PER_HOUR, true
+	case 0x0E:
+		return MeasurementUnits_LITRES_PER_MINUTE, true
+	case 0x0F:
+		return MeasurementUnits_LITRES_PER_SECOND, true
+	case 0x10:
+		return MeasurementUnits_LUX, true
+	case 0x11:
+		return MeasurementUnits_METRES, true
+	case 0x12:
+		return MeasurementUnits_METRES_PER_MINUTE, true
+	case 0x13:
+		return MeasurementUnits_METRES_PER_SECOND, true
+	case 0x14:
+		return MeasurementUnits_METRES_PER_S_SQUARED, true
+	case 0x15:
+		return MeasurementUnits_MOLE, true
+	case 0x16:
+		return MeasurementUnits_NEWTON_METRE, true
+	case 0x17:
+		return MeasurementUnits_NEWTONS, true
+	case 0x18:
+		return MeasurementUnits_OHMS, true
+	case 0x19:
+		return MeasurementUnits_PASCAL, true
+	case 0x1A:
+		return MeasurementUnits_PERCENT, true
+	case 0x1B:
+		return MeasurementUnits_DECIBELS, true
+	case 0x1C:
+		return MeasurementUnits_PPM, true
+	case 0x1D:
+		return MeasurementUnits_RPM, true
+	case 0x1E:
+		return MeasurementUnits_SECOND, true
+	case 0x1F:
+		return MeasurementUnits_MINUTES, true
+	case 0x20:
+		return MeasurementUnits_HOURS, true
+	case 0x21:
+		return MeasurementUnits_SIEVERTS, true
+	case 0x22:
+		return MeasurementUnits_STERADIAN, true
+	case 0x23:
+		return MeasurementUnits_TESLA, true
+	case 0x24:
+		return MeasurementUnits_VOLTS, true
+	case 0x25:
+		return MeasurementUnits_WATT_HOURS, true
+	case 0x26:
+		return MeasurementUnits_WATTS, true
+	case 0x27:
+		return MeasurementUnits_WEBERS, true
+	case 0xFE:
+		return MeasurementUnits_NO_UNITS, true
+	case 0xFF:
+		return MeasurementUnits_CUSTOM, true
+	}
+	return 0, false
+}
+
+func MeasurementUnitsByName(value string) (enum MeasurementUnits, ok bool) {
+	switch value {
+	case "CELSIUS":
+		return MeasurementUnits_CELSIUS, true
+	case "AMPS":
+		return MeasurementUnits_AMPS, true
+	case "ANGLE_DEGREES":
+		return MeasurementUnits_ANGLE_DEGREES, true
+	case "COULOMB":
+		return MeasurementUnits_COULOMB, true
+	case "BOOLEANLOGIC":
+		return MeasurementUnits_BOOLEANLOGIC, true
+	case "FARADS":
+		return MeasurementUnits_FARADS, true
+	case "HENRYS":
+		return MeasurementUnits_HENRYS, true
+	case "HERTZ":
+		return MeasurementUnits_HERTZ, true
+	case "JOULES":
+		return MeasurementUnits_JOULES, true
+	case "KATAL":
+		return MeasurementUnits_KATAL, true
+	case "KG_PER_M3":
+		return MeasurementUnits_KG_PER_M3, true
+	case "KILOGRAMS":
+		return MeasurementUnits_KILOGRAMS, true
+	case "LITRES":
+		return MeasurementUnits_LITRES, true
+	case "LITRES_PER_HOUR":
+		return MeasurementUnits_LITRES_PER_HOUR, true
+	case "LITRES_PER_MINUTE":
+		return MeasurementUnits_LITRES_PER_MINUTE, true
+	case "LITRES_PER_SECOND":
+		return MeasurementUnits_LITRES_PER_SECOND, true
+	case "LUX":
+		return MeasurementUnits_LUX, true
+	case "METRES":
+		return MeasurementUnits_METRES, true
+	case "METRES_PER_MINUTE":
+		return MeasurementUnits_METRES_PER_MINUTE, true
+	case "METRES_PER_SECOND":
+		return MeasurementUnits_METRES_PER_SECOND, true
+	case "METRES_PER_S_SQUARED":
+		return MeasurementUnits_METRES_PER_S_SQUARED, true
+	case "MOLE":
+		return MeasurementUnits_MOLE, true
+	case "NEWTON_METRE":
+		return MeasurementUnits_NEWTON_METRE, true
+	case "NEWTONS":
+		return MeasurementUnits_NEWTONS, true
+	case "OHMS":
+		return MeasurementUnits_OHMS, true
+	case "PASCAL":
+		return MeasurementUnits_PASCAL, true
+	case "PERCENT":
+		return MeasurementUnits_PERCENT, true
+	case "DECIBELS":
+		return MeasurementUnits_DECIBELS, true
+	case "PPM":
+		return MeasurementUnits_PPM, true
+	case "RPM":
+		return MeasurementUnits_RPM, true
+	case "SECOND":
+		return MeasurementUnits_SECOND, true
+	case "MINUTES":
+		return MeasurementUnits_MINUTES, true
+	case "HOURS":
+		return MeasurementUnits_HOURS, true
+	case "SIEVERTS":
+		return MeasurementUnits_SIEVERTS, true
+	case "STERADIAN":
+		return MeasurementUnits_STERADIAN, true
+	case "TESLA":
+		return MeasurementUnits_TESLA, true
+	case "VOLTS":
+		return MeasurementUnits_VOLTS, true
+	case "WATT_HOURS":
+		return MeasurementUnits_WATT_HOURS, true
+	case "WATTS":
+		return MeasurementUnits_WATTS, true
+	case "WEBERS":
+		return MeasurementUnits_WEBERS, true
+	case "NO_UNITS":
+		return MeasurementUnits_NO_UNITS, true
+	case "CUSTOM":
+		return MeasurementUnits_CUSTOM, true
+	}
+	return 0, false
+}
+
+func MeasurementUnitsKnows(value uint8) bool {
+	for _, typeValue := range MeasurementUnitsValues {
+		if uint8(typeValue) == value {
+			return true
+		}
+	}
+	return false
+}
+
+func CastMeasurementUnits(structType interface{}) MeasurementUnits {
+	castFunc := func(typ interface{}) MeasurementUnits {
+		if sMeasurementUnits, ok := typ.(MeasurementUnits); ok {
+			return sMeasurementUnits
+		}
+		return 0
+	}
+	return castFunc(structType)
+}
+
+func (m MeasurementUnits) GetLengthInBits() uint16 {
+	return 8
+}
+
+func (m MeasurementUnits) GetLengthInBytes() uint16 {
+	return m.GetLengthInBits() / 8
+}
+
+func MeasurementUnitsParse(readBuffer utils.ReadBuffer) (MeasurementUnits, error) {
+	val, err := readBuffer.ReadUint8("MeasurementUnits", 8)
+	if err != nil {
+		return 0, errors.Wrap(err, "error reading MeasurementUnits")
+	}
+	if enum, ok := MeasurementUnitsByValue(val); !ok {
+		log.Debug().Msgf("no value %x found for RequestType", val)
+		return MeasurementUnits(val), nil
+	} else {
+		return enum, nil
+	}
+}
+
+func (e MeasurementUnits) Serialize(writeBuffer utils.WriteBuffer) error {
+	return writeBuffer.WriteUint8("MeasurementUnits", 8, uint8(e), utils.WithAdditionalStringRepresentation(e.PLC4XEnumName()))
+}
+
+// PLC4XEnumName returns the name that is used in code to identify this enum
+func (e MeasurementUnits) PLC4XEnumName() string {
+	switch e {
+	case MeasurementUnits_CELSIUS:
+		return "CELSIUS"
+	case MeasurementUnits_AMPS:
+		return "AMPS"
+	case MeasurementUnits_ANGLE_DEGREES:
+		return "ANGLE_DEGREES"
+	case MeasurementUnits_COULOMB:
+		return "COULOMB"
+	case MeasurementUnits_BOOLEANLOGIC:
+		return "BOOLEANLOGIC"
+	case MeasurementUnits_FARADS:
+		return "FARADS"
+	case MeasurementUnits_HENRYS:
+		return "HENRYS"
+	case MeasurementUnits_HERTZ:
+		return "HERTZ"
+	case MeasurementUnits_JOULES:
+		return "JOULES"
+	case MeasurementUnits_KATAL:
+		return "KATAL"
+	case MeasurementUnits_KG_PER_M3:
+		return "KG_PER_M3"
+	case MeasurementUnits_KILOGRAMS:
+		return "KILOGRAMS"
+	case MeasurementUnits_LITRES:
+		return "LITRES"
+	case MeasurementUnits_LITRES_PER_HOUR:
+		return "LITRES_PER_HOUR"
+	case MeasurementUnits_LITRES_PER_MINUTE:
+		return "LITRES_PER_MINUTE"
+	case MeasurementUnits_LITRES_PER_SECOND:
+		return "LITRES_PER_SECOND"
+	case MeasurementUnits_LUX:
+		return "LUX"
+	case MeasurementUnits_METRES:
+		return "METRES"
+	case MeasurementUnits_METRES_PER_MINUTE:
+		return "METRES_PER_MINUTE"
+	case MeasurementUnits_METRES_PER_SECOND:
+		return "METRES_PER_SECOND"
+	case MeasurementUnits_METRES_PER_S_SQUARED:
+		return "METRES_PER_S_SQUARED"
+	case MeasurementUnits_MOLE:
+		return "MOLE"
+	case MeasurementUnits_NEWTON_METRE:
+		return "NEWTON_METRE"
+	case MeasurementUnits_NEWTONS:
+		return "NEWTONS"
+	case MeasurementUnits_OHMS:
+		return "OHMS"
+	case MeasurementUnits_PASCAL:
+		return "PASCAL"
+	case MeasurementUnits_PERCENT:
+		return "PERCENT"
+	case MeasurementUnits_DECIBELS:
+		return "DECIBELS"
+	case MeasurementUnits_PPM:
+		return "PPM"
+	case MeasurementUnits_RPM:
+		return "RPM"
+	case MeasurementUnits_SECOND:
+		return "SECOND"
+	case MeasurementUnits_MINUTES:
+		return "MINUTES"
+	case MeasurementUnits_HOURS:
+		return "HOURS"
+	case MeasurementUnits_SIEVERTS:
+		return "SIEVERTS"
+	case MeasurementUnits_STERADIAN:
+		return "STERADIAN"
+	case MeasurementUnits_TESLA:
+		return "TESLA"
+	case MeasurementUnits_VOLTS:
+		return "VOLTS"
+	case MeasurementUnits_WATT_HOURS:
+		return "WATT_HOURS"
+	case MeasurementUnits_WATTS:
+		return "WATTS"
+	case MeasurementUnits_WEBERS:
+		return "WEBERS"
+	case MeasurementUnits_NO_UNITS:
+		return "NO_UNITS"
+	case MeasurementUnits_CUSTOM:
+		return "CUSTOM"
+	}
+	return ""
+}
+
+func (e MeasurementUnits) String() string {
+	return e.PLC4XEnumName()
+}
diff --git a/plc4go/protocols/cbus/readwrite/model/StaticHelper.go b/plc4go/protocols/cbus/readwrite/model/StaticHelper.go
index 3438b8ccf..bbff83e21 100644
--- a/plc4go/protocols/cbus/readwrite/model/StaticHelper.go
+++ b/plc4go/protocols/cbus/readwrite/model/StaticHelper.go
@@ -231,3 +231,13 @@ func KnowsAirConditioningCommandTypeContainer(readBuffer utils.ReadBuffer) bool
 	}
 	return AirConditioningCommandTypeContainerKnows(readUint8)
 }
+
+func KnowsMeasurementCommandTypeContainer(readBuffer utils.ReadBuffer) bool {
+	oldPos := readBuffer.GetPos()
+	defer readBuffer.Reset(oldPos)
+	readUint8, err := readBuffer.ReadUint8("", 8)
+	if err != nil {
+		return false
+	}
+	return MeasurementCommandTypeContainerKnows(readUint8)
+}
diff --git a/plc4j/drivers/c-bus/src/main/java/org/apache/plc4x/java/cbus/readwrite/utils/StaticHelper.java b/plc4j/drivers/c-bus/src/main/java/org/apache/plc4x/java/cbus/readwrite/utils/StaticHelper.java
index 78a7ecea9..84902edea 100644
--- a/plc4j/drivers/c-bus/src/main/java/org/apache/plc4x/java/cbus/readwrite/utils/StaticHelper.java
+++ b/plc4j/drivers/c-bus/src/main/java/org/apache/plc4x/java/cbus/readwrite/utils/StaticHelper.java
@@ -216,4 +216,15 @@ public class StaticHelper {
         }
     }
 
+    public static boolean knowsMeasurementCommandTypeContainer(ReadBuffer readBuffer) {
+        int oldPos = readBuffer.getPos();
+        try {
+            return MeasurementCommandTypeContainer.isDefined(readBuffer.readUnsignedShort(8));
+        } catch (ParseException ignore) {
+            return false;
+        } finally {
+            readBuffer.reset(oldPos);
+        }
+    }
+
 }
diff --git a/protocols/c-bus/src/main/resources/protocols/cbus/c-bus.mspec b/protocols/c-bus/src/main/resources/protocols/cbus/c-bus.mspec
index d0f25e8cd..44fc5d57a 100644
--- a/protocols/c-bus/src/main/resources/protocols/cbus/c-bus.mspec
+++ b/protocols/c-bus/src/main/resources/protocols/cbus/c-bus.mspec
@@ -3262,6 +3262,78 @@
     [virtual uint  8  minute                    'minutesSinceSunday12AM%60'     ]
 ]
 
+[type MeasurementData
+    //TODO: golang doesn't like checking for null so we use that static call to check that the enum is known
+    [validation 'STATIC_CALL("knowsMeasurementCommandTypeContainer", readBuffer)' "no command type could be found" shouldFail=false]
+    [simple  MeasurementCommandTypeContainer      commandTypeContainer                                   ]
+    [virtual MeasurementCommandType               commandType          'commandTypeContainer.commandType']
+    [typeSwitch commandType
+        ['MEASUREMENT_EVENT'              *ChannelMeasurementData
+            [simple   uint 8            deviceId   ]
+            [simple   uint 8            channel    ]
+            [simple   MeasurementUnits  units      ]
+            [simple    int 8            multiplier ]
+            [simple   uint 8            msb        ]
+            [simple   uint 8            lsb        ]
+            [virtual  uint 16           rawValue    'msb<<8|lsb'            ]
+            [virtual  float 64          value       'rawValue*multiplier*10']
+        ]
+    ]
+]
+
+[enum uint 8 MeasurementUnits
+    ['0x00' CELSIUS                 ]
+    ['0x01' AMPS                    ]
+    ['0x02' ANGLE_DEGREES           ]
+    ['0x03' COULOMB                 ]
+    ['0x04' BOOLEANLOGIC            ]
+    ['0x05' FARADS                  ]
+    ['0x06' HENRYS                  ]
+    ['0x07' HERTZ                   ]
+    ['0x08' JOULES                  ]
+    ['0x09' KATAL                   ]
+    ['0x0A' KG_PER_M3               ]
+    ['0x0B' KILOGRAMS               ]
+    ['0x0C' LITRES                  ]
+    ['0x0D' LITRES_PER_HOUR         ]
+    ['0x0E' LITRES_PER_MINUTE       ]
+    ['0x0F' LITRES_PER_SECOND       ]
+    ['0x10' LUX                     ]
+    ['0x11' METRES                  ]
+    ['0x12' METRES_PER_MINUTE       ]
+    ['0x13' METRES_PER_SECOND       ]
+    ['0x14' METRES_PER_S_SQUARED    ]
+    ['0x15' MOLE                    ]
+    ['0x16' NEWTON_METRE            ]
+    ['0x17' NEWTONS                 ]
+    ['0x18' OHMS                    ]
+    ['0x19' PASCAL                  ]
+    ['0x1A' PERCENT                 ]
+    ['0x1B' DECIBELS                ]
+    ['0x1C' PPM                     ]
+    ['0x1D' RPM                     ]
+    ['0x1E' SECOND                  ]
+    ['0x1F' MINUTES                 ]
+    ['0x20' HOURS                   ]
+    ['0x21' SIEVERTS                ]
+    ['0x22' STERADIAN               ]
+    ['0x23' TESLA                   ]
+    ['0x24' VOLTS                   ]
+    ['0x25' WATT_HOURS              ]
+    ['0x26' WATTS                   ]
+    ['0x27' WEBERS                  ]
+    ['0xFE' NO_UNITS                ]
+    ['0xFF' CUSTOM                  ]
+]
+
+[enum uint 8 MeasurementCommandTypeContainer(MeasurementCommandType commandType, uint 5 numBytes)
+    ['0x0E' MeasurementCommandChannelMeasurementData    ['MEASUREMENT_EVENT',  '6']]
+]
+
+[enum uint 4 MeasurementCommandType
+    ['0x00' MEASUREMENT_EVENT              ]
+]
+
 [type ReplyOrConfirmation(CBusOptions cBusOptions, uint 16 messageLength, RequestContext requestContext)
     [peek    byte peekedByte                                                ]
     [virtual bit  isAlpha '(peekedByte >= 0x67) && (peekedByte <= 0x7A)'    ]