APIs

Show:
  1. "use strict";
  2. /**
  3. * @module opcua.address_space.AlarmsAndConditions
  4. */
  5.  
  6.  
  7. const util = require("util");
  8. const assert = require("node-opcua-assert").assert;
  9. const _ = require("underscore");
  10.  
  11. const StatusCodes = require("node-opcua-status-code").StatusCodes;
  12. const DataType = require("node-opcua-variant").DataType;
  13.  
  14. const UAAlarmConditionBase = require("./alarm_condition").UAAlarmConditionBase;
  15. const UAVariable = require("../ua_variable").UAVariable;
  16. const ConditionInfo = require("./condition").ConditionInfo;
  17. const DataValue = require("node-opcua-data-value").DataValue;
  18. const NodeId = require("node-opcua-nodeid").NodeId;
  19.  
  20. const AddressSpace =require("../address_space").AddressSpace;
  21. const Namespace = require("../namespace").Namespace;
  22. /**
  23. * @class UALimitAlarm
  24. * @constructor
  25. * @extends UAAlarmConditionBase
  26. */
  27. function UALimitAlarm() {
  28. /**
  29. * @property activeState
  30. * @type UATwoStateVariable
  31. */
  32.  
  33. }
  34. util.inherits(UALimitAlarm, UAAlarmConditionBase);
  35.  
  36. /**
  37. * @method getHighHighLimit
  38. * @return {Number}
  39. */
  40. UALimitAlarm.prototype.getHighHighLimit = function () {
  41. return this.highHighLimit.readValue().value.value;
  42. };
  43.  
  44. /**
  45. * @method getHighLimit
  46. * @return {Number}
  47. */
  48. UALimitAlarm.prototype.getHighLimit = function () {
  49. return this.highLimit.readValue().value.value;
  50. };
  51.  
  52. /**
  53. * @method getLowLimit
  54. * @return {Float}
  55. */
  56. UALimitAlarm.prototype.getLowLimit = function () {
  57. return this.lowLimit.readValue().value.value;
  58. };
  59.  
  60. /**
  61. * @method getLowLowLimit
  62. * @return {Float}
  63. */
  64. UALimitAlarm.prototype.getLowLowLimit = function () {
  65. return this.lowLowLimit.readValue().value.value;
  66. };
  67.  
  68. /**
  69. * @method setHighHighLimit
  70. * @param value {Float}
  71. */
  72. UALimitAlarm.prototype.setHighHighLimit = function (value) {
  73. assert(this.highHighLimit, "LimitAlarm instance must expose the optional HighHighLimit property");
  74. this.highHighLimit.setValueFromSource({ dataType: this._dataType, value: value });
  75.  
  76. };
  77.  
  78. /**
  79. * @method setHighLimit
  80. * @param value {Float}
  81. */
  82. UALimitAlarm.prototype.setHighLimit = function (value) {
  83. assert(this.highLimit, "LimitAlarm instance must expose the optional HighLimit property");
  84. this.highLimit.setValueFromSource({ dataType: this._dataType, value: value });
  85. };
  86.  
  87. /**
  88. * @method setLowLimit
  89. * @param value {Float}
  90. */
  91. UALimitAlarm.prototype.setLowLimit = function (value) {
  92. assert(this.lowLimit, "LimitAlarm instance must expose the optional LowLimit property");
  93. this.lowLimit.setValueFromSource({ dataType: this._dataType, value: value });
  94.  
  95. };
  96.  
  97. /**
  98. * @method setLowLowLimit
  99. * @param value {Float}
  100. */
  101. UALimitAlarm.prototype.setLowLowLimit = function (value) {
  102. assert(this.lowLowLimit, "LimitAlarm instance must expose the optional LowLowLimit property");
  103. this.lowLowLimit.setValueFromSource({ dataType: this._dataType, value: value });
  104. };
  105.  
  106. UALimitAlarm.prototype._onInputDataValueChange = function (dataValue) {
  107.  
  108. assert(dataValue instanceof DataValue);
  109. const alarm = this;
  110.  
  111. if (dataValue.statusCode === StatusCodes.BadWaitingForInitialData) {
  112. // we are not ready yet to use the input node value
  113. return;
  114. }
  115. if (dataValue.statusCode !== StatusCodes.Good) {
  116. // what shall we do ?
  117. alarm._signalNewCondition(null);
  118. return;
  119. }
  120. if (dataValue.value.dataType === DataType.Null) {
  121. // what shall we do ?
  122. alarm._signalNewCondition(null);
  123. return;
  124. }
  125. const value = dataValue.value.value;
  126. alarm._setStateBasedOnInputValue(value);
  127. };
  128.  
  129.  
  130. UALimitAlarm.prototype._watchLimits = function() {
  131.  
  132. const alarm = this;
  133. /// ----------------------------------------------------------------------
  134. /// Installing Limits monitored
  135. function _updateState() { alarm.updateState(); }
  136. if (alarm.highHighLimit) {alarm.highHighLimit.on("value_changed",_updateState);}
  137. if (alarm.highLimit) {alarm.highLimit.on("value_changed",_updateState);}
  138. if (alarm.lowLimit) {alarm.lowLimit.on("value_changed",_updateState);}
  139. if (alarm.lowLowLimit) {alarm.lowLowLimit.on("value_changed",_updateState);}
  140. };
  141.  
  142.  
  143.  
  144.  
  145.  
  146.  
  147.  
  148. exports.UALimitAlarm = UALimitAlarm;
  149.  
  150. /**
  151. * @method (static)UALimitAlarm.instantiate
  152. * @param namespace {Namespace}
  153. * @param limitAlarmTypeId
  154. * @param options
  155. * @param options.inputNode
  156. * @param options.optionals
  157. * @param options.highHighLimit {Double}
  158. * @param options.highLimit {Double}
  159. * @param options.lowLimit {Double}
  160. * @param options.lowLowLimit {Double}
  161. * @param data
  162. * @return {UALimitAlarm}
  163. */
  164. UALimitAlarm.instantiate = function (namespace, limitAlarmTypeId, options, data) {
  165. assert(namespace instanceof Namespace);
  166. const addressSpace = namespace.addressSpace;
  167. assert(addressSpace instanceof AddressSpace);
  168.  
  169. /* eslint max-instructions: off */
  170. // must provide a inputNode
  171. //xx assert(options.hasOwnProperty("conditionOf")); // must provide a conditionOf
  172. assert(options.hasOwnProperty("inputNode"), "UALimitAlarm.instantiate: options must provide the inputNode");
  173.  
  174. options.optionals = options.optionals || [];
  175. let count = 0;
  176. if (options.hasOwnProperty("highHighLimit")) {
  177. options.optionals.push("HighHighLimit");
  178. options.optionals.push("HighHighState");
  179. count++;
  180. }
  181. if (options.hasOwnProperty("highLimit")) {
  182. options.optionals.push("HighLimit");
  183. options.optionals.push("HighState");
  184. count++;
  185. }
  186. if (options.hasOwnProperty("lowLimit")) {
  187. options.optionals.push("LowLimit");
  188. options.optionals.push("LowState");
  189. count++;
  190. }
  191. if (options.hasOwnProperty("lowLowLimit")) {
  192. options.optionals.push("LowLowLimit");
  193. options.optionals.push("LowLowState");
  194. count++;
  195. }
  196.  
  197. //xx assert(options.optionals,"must provide an optionals");
  198. const alarmNode = UAAlarmConditionBase.instantiate(namespace, limitAlarmTypeId, options, data);
  199. Object.setPrototypeOf(alarmNode, UALimitAlarm.prototype);
  200.  
  201. assert(alarmNode.conditionOfNode() !== null);
  202.  
  203. const inputNode = addressSpace._coerceNode(options.inputNode);
  204. assert(inputNode, "Expecting a valid input node");
  205. assert(inputNode instanceof UAVariable);
  206.  
  207. // ----------------------- Install Limit Alarm specifics
  208. // from spec 1.03:
  209. // Four optional limits are defined that configure the states of the derived limit Alarm Types.
  210. // These Properties shall be set for any Alarm limits that are exposed by the derived limit Alarm
  211. // Types. These Properties are listed as optional but at least one is required. For cases where
  212. // an underlying system cannot provide the actual value of a limit, the limit Property shall still be
  213. // provided, but will have its AccessLevel set to not readable. It is assumed that the limits are
  214. // described using the same Engineering Unit that is assigned to the variable that is the source
  215. // of the alarm. For Rate of change limit alarms, it is assumed this rate is units per second
  216. // unless otherwise specified.
  217. if (count === 0) {
  218. throw new Error("at least one limit is required");
  219. }
  220.  
  221. const dataType = addressSpace.findCorrespondingBasicDataType(options.inputNode.dataType);
  222. alarmNode._dataType = dataType;
  223.  
  224. if (options.hasOwnProperty("highHighLimit")) {
  225. alarmNode.setHighHighLimit(options.highHighLimit);
  226. }
  227. if (options.hasOwnProperty("highLimit")) {
  228. alarmNode.setHighLimit(options.highLimit);
  229. }
  230. if (options.hasOwnProperty("lowLimit")) {
  231. alarmNode.setLowLimit(options.lowLimit);
  232. }
  233. if (options.hasOwnProperty("lowLowLimit")) {
  234. alarmNode.setLowLowLimit(options.lowLowLimit);
  235. }
  236.  
  237. /*
  238. * The InputNode Property provides the NodeId of the Variable the Value of which is used as
  239. * primary input in the calculation of the Alarm state. If this Variable is not in the AddressSpace,
  240. * a Null NodeId shall be provided. In some systems, an Alarm may be calculated based on
  241. * multiple Variables Values; it is up to the system to determine which Variable’s NodeId is used.
  242. */
  243. assert(alarmNode.inputNode instanceof UAVariable);
  244. alarmNode.inputNode.setValueFromSource({ dataType: "NodeId", value: inputNode.nodeId });
  245.  
  246.  
  247. // install inputNode monitoring for change
  248. alarmNode._installInputNodeMonitoring(options.inputNode);
  249. alarmNode._watchLimits();
  250.  
  251. return alarmNode;
  252. };
  253.  
  254. UALimitAlarm.prototype.evaluateConditionsAfterEnabled = function () {
  255. assert(this.getEnabledState() === true);
  256. //simulate input value event
  257. const alarmNode = this;
  258. const dataValue = alarmNode.getInputNodeNode().readValue();
  259. alarmNode._onInputDataValueChange(dataValue);
  260. };
  261.