diff --git a/libnymea-zigbee/zcl/smartenergy/zigbeeclustermetering.cpp b/libnymea-zigbee/zcl/smartenergy/zigbeeclustermetering.cpp index cc5353c..65f4302 100644 --- a/libnymea-zigbee/zcl/smartenergy/zigbeeclustermetering.cpp +++ b/libnymea-zigbee/zcl/smartenergy/zigbeeclustermetering.cpp @@ -1,5 +1,6 @@ #include "zigbeeclustermetering.h" +#include #include Q_DECLARE_LOGGING_CATEGORY(dcZigbeeCluster) @@ -64,3 +65,52 @@ void ZigbeeClusterMetering::setAttribute(const ZigbeeClusterAttribute &attribute qCWarning(dcZigbeeCluster()) << "Unhandled attribute change:" << attribute; } } + +void ZigbeeClusterMetering::processDataIndication(ZigbeeClusterLibrary::Frame frame) +{ + switch (m_direction) { + case Client: + qCWarning(dcZigbeeCluster()) << "Metering: Unhandled ZCL indication in" << m_node << m_endpoint << this << frame; + break; + case Server: { + ServerCommand command = static_cast(frame.header.command); + switch (command) { + case CommandDisplayMessage: { + QDataStream stream(frame.payload); + stream.setByteOrder(QDataStream::LittleEndian); + quint32 messageId, time; + quint16 durationInMinutes; + quint8 messageControl; + stream >> messageId >> messageControl >> time >> durationInMinutes; + + char messageData[2048]; // At max 2KB, realistically we'll only ever see < 80B in here as larger messages require both ends to negotiate on a larger PDU, however, if the backend supports it, it *may* happen. + int messageLength = stream.readRawData(messageData, 2048); + QByteArray message(messageData, messageLength); + MessageTransmission messageTransmission = static_cast((messageControl & 0xC0) >> 6); + MessagePriority priority = static_cast((messageControl & 0x30) >> 4); + bool confirmationRequired = (messageControl & 0x01) == 1; + + qCWarning(dcZigbeeCluster()) << "Display message received!" << messageId << messageControl << time << durationInMinutes << message; + emit showMessage(messageId, message, time, durationInMinutes, messageTransmission, priority, confirmationRequired); + break; + } + case ClientCommandCancelMessage: { + QDataStream stream(frame.payload); + stream.setByteOrder(QDataStream::LittleEndian); + quint32 messageId; + quint8 messageControl; + stream >> messageId >> messageControl; + MessageTransmission messageTransmission = static_cast((messageControl & 0xC0) >> 6); + MessagePriority priority = static_cast((messageControl & 0x30) >> 4); + bool confirmationRequired = (messageControl & 0x01) == 1; + qCDebug(dcZigbeeCluster()) << "Metering: Cancel message command received" << messageId << messageControl; + emit cancelMessage(messageId, messageTransmission, priority, confirmationRequired); + break; + } + default: + qCDebug(dcZigbeeCluster()) << "Ignoring out of spec metering cluster ZCL indication:" << m_node << m_endpoint << this << frame; + } + break; + } + } +} diff --git a/libnymea-zigbee/zcl/smartenergy/zigbeeclustermetering.h b/libnymea-zigbee/zcl/smartenergy/zigbeeclustermetering.h index e8c1d0c..524c8db 100644 --- a/libnymea-zigbee/zcl/smartenergy/zigbeeclustermetering.h +++ b/libnymea-zigbee/zcl/smartenergy/zigbeeclustermetering.h @@ -555,6 +555,36 @@ public: }; Q_ENUM(AlarmCode) + enum ClientCommand { + CommandGetProfile = 0x00, + CommandRequestMirrorResponse = 0x01, + CommandMirrorRemoved = 0x02, + CommandRequestFastPollMode = 0x03 + }; + Q_ENUM(ClientCommand) + + enum ServerCommand { + CommandDisplayMessage = 0x00, + ClientCommandCancelMessage = 0x01 + }; + Q_ENUM(ServerCommand) + + enum MessageTransmission { + MessageTransmissionNormal = 0x0, + MessageTransmissionNormalAndAnonymousInterPan = 0x1, + MessageTransmissionAnonymousInterPan = 0x2 + }; + Q_ENUM(MessageTransmission) + + enum MessagePriority { + MessagePriorityLow = 0x0, + MessagePriorityMedium = 0x1, + MessagePriorityHigh = 0x2, + MessagePriorityCritical = 0x3 + }; + Q_ENUM(MessagePriority) + + explicit ZigbeeClusterMetering(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Direction direction, QObject *parent = nullptr); // Used to refresh formatting attributes (multiplier/divisor) @@ -570,8 +600,12 @@ signals: void currentSummationDeliveredChanged(quint64 currentSummationDelivered); void instantaneousDemandChanged(qint32 instantaneousDemand); + void showMessage(quint32 messageId, const QString &message, quint32 time, quint16 durationInMinutes, MessageTransmission transmission, MessagePriority priority, bool confirmationRequired); + void cancelMessage(quint32 messageId, MessageTransmission transmission, MessagePriority priority, bool confirmationRequired); + private: void setAttribute(const ZigbeeClusterAttribute &attribute) override; + void processDataIndication(ZigbeeClusterLibrary::Frame frame) override; quint32 m_multiplier = 1; quint32 m_divisor = 1;