APIs

Show:
"use strict";


var _ = require("underscore");
var assert = require("node-opcua-assert");
var opcua = require("node-opcua");
var StatusCodes = opcua.StatusCodes;
var DataType = opcua.DataType;
var standardUnits = opcua.standardUnits;

var doDebug = false;

/***
 * @method createHVACSystem
 *
 * @startuml
 *
 * class HVACModuleType {
 * }
 * HVACModuleType -up-> ObjectType
 * HVACModuleType o-down-> ExteriorTemperatureSensor     << (P,#F0F0FF)TemperatureSensorType >>
 * HVACModuleType o-down-> InteriorTemperatureSensor     << (P,#F0F0FF)TemperatureSensorType >>
 * HVACModuleType o-down-> TargetTemperature     << (P,#F0F0FF)TemperatureSensorType >>
 * HVACModuleType o-down-> HVACEnabledEventType  << (E,#00F0FF)BaseEventType >>
 * HVACModuleType o-down-> HVACDisabledEventType << (E,#00F0FF)BaseEventType >>
 * HVACModuleType o-left-> SetTargetTemperature<< (M,#ABFFF0) >>
 * HVACModuleType o-left---> Enable  << (M,#ABFFF0) >>
 * HVACModuleType o-left---> Disable << (M,#ABFFF0) >>
 * AnalogItemType -up-> DataItemType
 * DataItemType -up-> BaseDataVariableType
 * @enduml
 *
 * compact version
 * @startuml
 *
 * class HVACModuleType << (C,F0F0F0)ObjectType >> {
 *   ExteriorTemperatureSensor: AnalogItemType
 *   InteriorTemperatureSensor: AnalogItemType
 *   TargetTemperature : Variable
 *   --------
 *   HVACEnabledEventType
 *   HVACDisabledEventType
 *   --------
 *   SetTargetTemperature
 *   Enable
 *   Disable
 * }
 * @enduml
 *
 * @param addressSpace
 * @return {*}
 */
exports.createHVACSystem = function(addressSpace) {


    var HVACEnabledEventType = addressSpace.addEventType({
        browseName:"HVACEnabledEventType"
    });

    var HVACDisabledEventType = addressSpace.addEventType({
        browseName:"HVACDisabledEventType"
    });

    var HVACModuleType = addressSpace.addObjectType({
        browseName: "HVACModuleType"
    });


    addressSpace.addAnalogDataItem({
        componentOf: HVACModuleType,
        browseName: "ExteriorTemperature",
        accessLevel: "CurrentRead",
        valuePrecision: 0.01,
        instrumentRange: { low: -70, high: 120},
        engineeringUnitsRange: { low: -100, high: 200},
        engineeringUnits: standardUnits.degree_celsius, // � Celsius
        description: "External temperature Sensor",
        minimumSamplingInterval: 500,
        dataType: "Double",
        modellingRule: "Mandatory"
    });

    addressSpace.addAnalogDataItem({
        componentOf: HVACModuleType,
        browseName: "InteriorTemperature",
        accessLevel: "CurrentRead",
        valuePrecision: 0.01,
        instrumentRange: { low: -70, high: 120},
        engineeringUnitsRange: { low: -100, high: 200},
        engineeringUnits: standardUnits.degree_celsius,
        description: "External temperature Sensor",
        minimumSamplingInterval: 500,
        dataType: "Double",
        modellingRule: "Mandatory"
    });


    // EURange (10,+27)
    addressSpace.addAnalogDataItem({
        modellingRule: "Mandatory",
        componentOf: HVACModuleType,
        browseName: "TargetTemperature",
        minimumSamplingInterval: 0, // could be event Based
        dataType: "Double",
        instrumentRange: { low: -70, high: 120},
        engineeringUnitsRange: { low: -100, high: 200}
    });

    addressSpace.addMethod(HVACModuleType,{
        modellingRule: "Mandatory",
        browseName: "Enable",
        description: "Enable the hvac system",
        alwaysGeneratesEvent: HVACEnabledEventType,
        inputArguments: [],
        outputArguments: []
    });

    addressSpace.addMethod(HVACModuleType,{
        modellingRule: "Mandatory",
        browseName: "Disable",
        description: "Disable the hvac system",
        alwaysGeneratesEvent: HVACDisabledEventType,
        inputArguments: [],
        outputArguments: []
    });

    addressSpace.addMethod(HVACModuleType,{
        modellingRule: "Mandatory",
        browseName: "SetTargetTemperature",
        inputArguments: [
            {
                name: "targetTemperature",
                description: {text: "specifies the target temperature"},
                dataType: DataType.Double
            }
        ],
        outputArguments: []
    });

    addressSpace.addTwoStateDiscrete({
        modellingRule: "Mandatory",
        componentOf: HVACModuleType,
        browseName: "MainSwitch",
        trueState: "Up/ON",
        falseState: "Down/OFF",
        value: false
    });


    var myHVAC = HVACModuleType.instantiate({
        browseName: "MyHVAC1"
    });

    // initialize interiorTemperature :
    myHVAC.interiorTemperature.setValueFromSource({dataType:DataType.Double,value:16});

    myHVAC.targetTemperature.setValueFromSource({dataType:DataType.Double,value:16});

    // bind the method
    myHVAC.enable.bindMethod(function(inputArguments, context, callback) {
        var myResult = {
            statusCode: StatusCodes.Good
        };
        callback(null,myResult);
    });

    function updateInteriorTemperature() {

        var currentTemp = myHVAC.interiorTemperature.readValue().value.value;

        var targetTemp  = myHVAC.targetTemperature.readValue().value.value;

        var newInteriorTemp =  currentTemp + (targetTemp - currentTemp) /100.0;

        myHVAC.interiorTemperature.setValueFromSource({dataType: DataType.Float, value: newInteriorTemp});

        //xx console.log("Tick = target temp = ",targetTemp," current =",currentTemp," new= ",newInteriorTemp);
    }

    var timerId = setInterval(updateInteriorTemperature,60);

    myHVAC.on("dispose",function() {
        clearInterval(timerId);
    });

    //xx console.log(" => ",myHVAC.setTargetTemperature.inputArguments.readValue().toString());

    // bind the method
    myHVAC.setTargetTemperature.bindMethod(function(inputArguments, context, callback) {

        if (doDebug) {
            console.log(" In SetTargetTemperature".cyan.bold);
            console.log("inputArguments",inputArguments[0].toString());
        }

        var targetTemperature = inputArguments[0];
        assert(targetTemperature instanceof opcua.Variant);

        var variable = myHVAC.targetTemperature;

        if (doDebug) {
            console.log("instrumentRange=", myHVAC.targetTemperature.instrumentRange.readValue().value.toString());
            console.log("instrumentRange=", HVACModuleType.targetTemperature.instrumentRange.readValue().value.toString());
        }
        var s = variable.isValueInRange(targetTemperature);
        if (s !== StatusCodes.Good) {
            console.log(" Invalid Value specified for targetTemperature".red.bold);
            return callback(null, { statusCode: s });
        }


        variable.setValueFromSource(targetTemperature,StatusCodes.Good);

        callback();

    });

    return myHVAC.nodeId.toString();
};