summaryrefslogtreecommitdiffstats
path: root/src/BobinkNode.h
blob: c37a88387c85b30a804a225e650dcd019d2dfb33 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
/**
 * @file   BobinkNode.h
 * @brief  QML component representing a single OPC UA node.
 *
 * Inherits QQuickItem so that monitoring is automatically tied to
 * visibility: when the item (or any ancestor) becomes invisible
 * (e.g. StackView navigates away, Loader unloads), the monitored
 * item is removed from the subscription.  When visible again,
 * monitoring resumes.
 */
#ifndef BOBINKNODE_H
#define BOBINKNODE_H

#include <QDateTime>
#include <QHash>
#include <QOpcUaNode>
#include <QQuickItem>

class BobinkNode : public QQuickItem
{
  Q_OBJECT
  QML_ELEMENT

  Q_PROPERTY (QString nodeId READ nodeId WRITE setNodeId NOTIFY nodeIdChanged)
  Q_PROPERTY (QVariant value READ value WRITE setValue NOTIFY valueChanged)
  Q_PROPERTY (NodeStatus status READ status NOTIFY statusChanged)
  Q_PROPERTY (QDateTime sourceTimestamp READ sourceTimestamp NOTIFY
                  sourceTimestampChanged)
  Q_PROPERTY (QDateTime serverTimestamp READ serverTimestamp NOTIFY
                  serverTimestampChanged)

public:
  explicit BobinkNode (QQuickItem *parent = nullptr);
  ~BobinkNode () override;

  /// Simplified OPC UA status severity.
  enum NodeStatus
  {
    Good,
    Uncertain,
    Bad
  };
  Q_ENUM (NodeStatus)

  QString nodeId () const;
  void setNodeId (const QString &id);

  QVariant value () const;
  /** Setting value writes to the server; the property updates when
   *  the server confirms via the monitored data change. */
  void setValue (const QVariant &value);

  NodeStatus status () const;
  QDateTime sourceTimestamp () const;
  QDateTime serverTimestamp () const;

  /** Read an attribute on demand (DisplayName, Description, DataType, …).
   *  Result arrives asynchronously via attributeRead(). */
  Q_INVOKABLE void readAttribute (const QString &attributeName);

signals:
  void nodeIdChanged ();
  void valueChanged ();
  void statusChanged ();
  void sourceTimestampChanged ();
  void serverTimestampChanged ();

  /** Emitted when a readAttribute() call completes. */
  void attributeRead (const QString &attributeName, const QVariant &value);

  /** Emitted when a write to the server fails. */
  void writeError (const QString &message);

protected:
  void componentComplete () override;
  void itemChange (ItemChange change, const ItemChangeData &data) override;

private:
  void startMonitoring ();
  void stopMonitoring ();

  void handleDataChange (QOpcUa::NodeAttribute attr, const QVariant &val);
  void handleAttributeUpdated (QOpcUa::NodeAttribute attr,
                               const QVariant &val);
  void handleAttributeWritten (QOpcUa::NodeAttribute attr,
                               QOpcUa::UaStatusCode statusCode);
  void handleClientConnectedChanged ();
  void handleAttributeReadFinished (QOpcUa::NodeAttributes attrs);
  void handleEnableMonitoringFinished (QOpcUa::NodeAttribute attr,
                                       QOpcUa::UaStatusCode statusCode);
  void handleDisableMonitoringFinished (QOpcUa::NodeAttribute attr,
                                        QOpcUa::UaStatusCode statusCode);

  static NodeStatus statusFromCode (QOpcUa::UaStatusCode code);
  static QOpcUa::NodeAttribute attributeFromName (const QString &name);
  static QLatin1StringView nameFromAttribute (QOpcUa::NodeAttribute attr);

  QString m_nodeId;
  QVariant m_value;
  NodeStatus m_status = Bad;
  QDateTime m_sourceTimestamp;
  QDateTime m_serverTimestamp;

  QOpcUaNode *m_opcuaNode = nullptr;
  bool m_componentComplete = false;

  /** Tracks in-flight readAttribute() requests (enum → original name). */
  QHash<QOpcUa::NodeAttribute, QString> m_pendingReads;
};

#endif // BOBINKNODE_H