QtKNX - converting messages to human readable numbers
-
Hi all.
I would like to convert a KNX byte array of this form "0x061004200017044c25002900bce0110408040300800078" to a human readable number (float/double).
In this case I understand how to convert from 0078 to 1.2, but I do not wish to manually inspect the udp packets and do numeric conversions if the Qt classes already have functions that do that.
What are the best practices for achieving this? Any pointers to relevant examples?
Although the documentation shows how to grab these udp messages, I could not find relevant information in the documentation or in the examples to help me achieve this.
Ideally I would like to create something generic like a QKnxDatapointType type by giving it a byte array (as above), read the group address (ie 1/0/4), (cross reference the group address with the type for that address stored in a DB to determine what type/subtype it is), set the main type/sub type (ie 9.001) in that object and call a 'value()' function to convert it to a float/double.
Does QtKNX allow one to examine all parts from the "0x061004200017044c25002900bce0110408040300800078" message and extract the value, group address and other fields?
Any help/pointers to something I missed will be much appreciated.
Thanks,
Michalis -
Hi all.
I would like to convert a KNX byte array of this form "0x061004200017044c25002900bce0110408040300800078" to a human readable number (float/double).
In this case I understand how to convert from 0078 to 1.2, but I do not wish to manually inspect the udp packets and do numeric conversions if the Qt classes already have functions that do that.
What are the best practices for achieving this? Any pointers to relevant examples?
Although the documentation shows how to grab these udp messages, I could not find relevant information in the documentation or in the examples to help me achieve this.
Ideally I would like to create something generic like a QKnxDatapointType type by giving it a byte array (as above), read the group address (ie 1/0/4), (cross reference the group address with the type for that address stored in a DB to determine what type/subtype it is), set the main type/sub type (ie 9.001) in that object and call a 'value()' function to convert it to a float/double.
Does QtKNX allow one to examine all parts from the "0x061004200017044c25002900bce0110408040300800078" message and extract the value, group address and other fields?
Any help/pointers to something I missed will be much appreciated.
Thanks,
MichalisWhen you know the format of the message you can get the single bytes with e.g. QByteArray::at() or QByteArray::mid() and convert them to the desired format accordingly.
-
When you know the format of the message you can get the single bytes with e.g. QByteArray::at() or QByteArray::mid() and convert them to the desired format accordingly.
@Christian-Ehrlicher
Hi Christian.
Thanks for trying to help.As I mentioned above, I am able to work with byte arrays and manually parse the knx byte array (knx ip frame) and convert to a numeric value manually.
What I am looking for is for a more proper way to do it and to see if there are any good resources out there.
Currently I can do this by extracting the two bytes of interest:
======================
auto ba = QByteArray::fromRawData("\x00\x78", 2);
auto knx_ba = QKnxByteArray::fromByteArray(ba);QKnxTemperatureCelsius temp; temp.setBytes(knx_ba, 0, knx_ba.size()); qDebug() << "type: " << temp.type(); qDebug() << "subtype: " << temp.subType(); qDebug() << "coefficient: " << temp.coefficient(); qDebug() << "hex: " << temp.bytes().toHex(); qDebug() << "description: " << temp.description(); qDebug() << "value: " << temp.value(); qDebug() << "----------"; QKnxDatapointType dpt(QKnxDatapointType::Type::DptTemperatureCelsius, 2); dpt.setBytes(knx_ba, 0, dpt.size()); qDebug() << "type: " << dpt.type(); qDebug() << "subtype: " << dpt.subType(); qDebug() << "coefficient: " << dpt.coefficient(); qDebug() << "hex: " << dpt.bytes().toHex(); qDebug() << "description: " << dpt.description(); //qDebug() << "value: " << dpt.value(); There is no value() function for this type
and get this result in the terminal:
type: QKnxDatapointType::Type::DptTemperatureCelsius
subtype: 1
coefficient: 1
hex: "0078"
description: "Temperature in degree Celsius"
value: 1.2type: QKnxDatapointType::Type::DptTemperatureCelsius
subtype: 1
coefficient: 1
hex: "0078"
description: ""=========================
It would be nice if there was a value() function for QKnxDatapointType that could return a number (given that I provide the type/subtype). This way I would not need to do manual conversions on 2 byte, 4 byte floats/int types etc.
Regards,
Michalis -
@Christian-Ehrlicher
Hi Christian.
Thanks for trying to help.As I mentioned above, I am able to work with byte arrays and manually parse the knx byte array (knx ip frame) and convert to a numeric value manually.
What I am looking for is for a more proper way to do it and to see if there are any good resources out there.
Currently I can do this by extracting the two bytes of interest:
======================
auto ba = QByteArray::fromRawData("\x00\x78", 2);
auto knx_ba = QKnxByteArray::fromByteArray(ba);QKnxTemperatureCelsius temp; temp.setBytes(knx_ba, 0, knx_ba.size()); qDebug() << "type: " << temp.type(); qDebug() << "subtype: " << temp.subType(); qDebug() << "coefficient: " << temp.coefficient(); qDebug() << "hex: " << temp.bytes().toHex(); qDebug() << "description: " << temp.description(); qDebug() << "value: " << temp.value(); qDebug() << "----------"; QKnxDatapointType dpt(QKnxDatapointType::Type::DptTemperatureCelsius, 2); dpt.setBytes(knx_ba, 0, dpt.size()); qDebug() << "type: " << dpt.type(); qDebug() << "subtype: " << dpt.subType(); qDebug() << "coefficient: " << dpt.coefficient(); qDebug() << "hex: " << dpt.bytes().toHex(); qDebug() << "description: " << dpt.description(); //qDebug() << "value: " << dpt.value(); There is no value() function for this type
and get this result in the terminal:
type: QKnxDatapointType::Type::DptTemperatureCelsius
subtype: 1
coefficient: 1
hex: "0078"
description: "Temperature in degree Celsius"
value: 1.2type: QKnxDatapointType::Type::DptTemperatureCelsius
subtype: 1
coefficient: 1
hex: "0078"
description: ""=========================
It would be nice if there was a value() function for QKnxDatapointType that could return a number (given that I provide the type/subtype). This way I would not need to do manual conversions on 2 byte, 4 byte floats/int types etc.
Regards,
Michalis@Michalis_SP said in QtKNX - converting messages to human readable numbers:
. This way I would not need to do manual conversions on 2 byte, 4 byte floats/int types etc.
Yes, you have to do it by your own since Qt can't know the presentation of your bytes. When you need endian conversion you can use helper functions from Qt: https://doc.qt.io/qt-6/qtendian.html
-
@Christian-Ehrlicher
Hi Christian.
Thanks for trying to help.As I mentioned above, I am able to work with byte arrays and manually parse the knx byte array (knx ip frame) and convert to a numeric value manually.
What I am looking for is for a more proper way to do it and to see if there are any good resources out there.
Currently I can do this by extracting the two bytes of interest:
======================
auto ba = QByteArray::fromRawData("\x00\x78", 2);
auto knx_ba = QKnxByteArray::fromByteArray(ba);QKnxTemperatureCelsius temp; temp.setBytes(knx_ba, 0, knx_ba.size()); qDebug() << "type: " << temp.type(); qDebug() << "subtype: " << temp.subType(); qDebug() << "coefficient: " << temp.coefficient(); qDebug() << "hex: " << temp.bytes().toHex(); qDebug() << "description: " << temp.description(); qDebug() << "value: " << temp.value(); qDebug() << "----------"; QKnxDatapointType dpt(QKnxDatapointType::Type::DptTemperatureCelsius, 2); dpt.setBytes(knx_ba, 0, dpt.size()); qDebug() << "type: " << dpt.type(); qDebug() << "subtype: " << dpt.subType(); qDebug() << "coefficient: " << dpt.coefficient(); qDebug() << "hex: " << dpt.bytes().toHex(); qDebug() << "description: " << dpt.description(); //qDebug() << "value: " << dpt.value(); There is no value() function for this type
and get this result in the terminal:
type: QKnxDatapointType::Type::DptTemperatureCelsius
subtype: 1
coefficient: 1
hex: "0078"
description: "Temperature in degree Celsius"
value: 1.2type: QKnxDatapointType::Type::DptTemperatureCelsius
subtype: 1
coefficient: 1
hex: "0078"
description: ""=========================
It would be nice if there was a value() function for QKnxDatapointType that could return a number (given that I provide the type/subtype). This way I would not need to do manual conversions on 2 byte, 4 byte floats/int types etc.
Regards,
Michalis@Michalis_SP you can try using QDataStream on the ByteArray and stream the values out, maybe you're lucky and the conversion fits :D
-
@Michalis_SP you can try using QDataStream on the ByteArray and stream the values out, maybe you're lucky and the conversion fits :D
@J-Hilk Thanks for the response but I am not looking at manually assembling the bytes to get a value and then multiplying it with some coefficient.
I was hoping that the QtKNX classes could do that for me.
There is a fixed datapoint type class (QKnxFixedSizeDatapointType) and a lot for other int/float classes that inherit from it. I was hoping that by choosing the correct type, I could get the conversion and multiplication done for me.List of classes listed here: https://doc.qt.io/qt-5/qtknx-module.html
Looking at the Qt source code, it looks like the value() function does not even do the multiplication with the coefficient in some cases.
For QKnx2ByteFloat::value() there is no clear coefficient multiplication but there is a hardcoded multiplication by 0.01 see:
https://github.com/qt/qtknx/blob/dev/src/knx/dpt/qknx2bytefloat.cppfloat QKnx2ByteFloat::value() const { quint16 temp = QKnxUtils::QUint16::fromBytes(bytes()); quint16 encodedM = (temp & 0x87ff); // Turning on bits reserved for E. // Only needed for reinterpretation of negative values if (encodedM > 2047) encodedM += 0x7800; qint16 M = qint16(encodedM); quint8 E = (temp & 0x7800) >> 11; return float(0.01 * (M) * qPow(2, qreal(E))); }
For QKnx2ByteSignedValue:value() there is a coefficient multiplication:
double QKnx2ByteSignedValue::value() const { return qint16(QKnxUtils::QUint16::fromBytes(bytes())) * coefficient(); }
For QKnx4ByteSignedValue::value() there is no multiplication:
qint32 QKnx4ByteSignedValue::value() const { return qint32(QKnxUtils::QUint32::fromBytes(bytes())); }
So how does one know when to manually multiply with a coefficient? Are we assuming that no QKnx2ByteFloat, QKnx4ByteSignedValue values will ever need multiplying with a coefficient, or will I have to manually subclass those?
Would it not be better to always do the multiplication and just have a default coefficient of 1?