function Device(data, logger, _events) {
    var property = { id: data.id, name: data.name };        // Device property (name, id)
    var status = DeviceStatusEnum.INIT;                     // Current status (StateMachine)
    var events = _events;                                   // Events to commit change to runtime
    var comm;                                               // Interface to OPCUA/S7 Device
    var currentCmd = null;                                  // Current Command (StateMachine)
    var deviceCheckStatus = null;                           // TimerInterval to check Device status (connection)
    var devicePolling = null;                               // TimerInterval to polling read device value

    if (data.type === DeviceEnum.S7) {
        comm = S7client.create(data, logger, events);
    } else if (data.type === DeviceEnum.OPCUA) {
        comm = OpcUAclient.create(data, logger, events);
    } else if (data.type === DeviceEnum.ModbusRTU || data.type === DeviceEnum.ModbusTCP) {
        comm = MODBUSclient.create(data, logger, events);        
    }

    /**
     * Start StateMachine, init and start TimerInterval to check Device status
     */
    this.start = function () {
        currentCmd = DeviceCmdEnum.START;
        if (status === DeviceStatusEnum.INIT) {
            logger.info(property.name + ': ' + currentCmd);
            var self = this;
            this.checkStatus();
            deviceCheckStatus = setInterval(function () {
                self.checkStatus();
            }, DEVICE_CHECK_STATUS_INTERVAL);
        }
    }

    /**
     * Stop StateMachine, Close Device connection, break all TimerInterval (Device status/polling)
     */
    this.stop = function () {
        return new Promise(function (resolve, reject) {
            currentCmd = DeviceCmdEnum.STOP;
            logger.info(property.name + ': ' + currentCmd);
            if (devicePolling) {
                clearInterval(devicePolling);
                devicePolling = null;
            }
            if (deviceCheckStatus) {
                clearInterval(deviceCheckStatus);
                deviceCheckStatus = null;
            }
            comm.disconnect().then(function () {
                status = DeviceStatusEnum.INIT;
                resolve();
            });
        });
    }

    /**
     * Check the Device connection, Reconnect
     */
    this.checkStatus = function () {
        if (status === DeviceStatusEnum.INIT && currentCmd === DeviceCmdEnum.START) {
            this.connect().then(function () {
                status = DeviceStatusEnum.IDLE;
            }).catch(function (err) {
                // devices.woking = null;
            });
        } else if (status === DeviceStatusEnum.IDLE && !comm.isConnected()) {
            status = DeviceStatusEnum.INIT;
            if (devicePolling) {
                clearInterval(devicePolling);
                devicePolling = null;
            }
        }
    }

    /**
     * Call Device to polling
     */
    this.polling = function () {
        comm.polling();
    }

    /**
     * Call Device to connect and start TimerInterval for read value polling
     */
    this.connect = function () {
        var self = this;
        if (data.type === DeviceEnum.ModbusRTU) {
            comm.init(MODBUSclient.ModbusTypes.RTU);
        } else if (data.type === DeviceEnum.ModbusTCP) {
            comm.init(MODBUSclient.ModbusTypes.TCP);
        }
        return comm.connect().then(function () {
            devicePolling = setInterval(function () {
                self.polling();
            }, DEVICE_POLLING_INTERVAL);
        });
    }

    /**
     * Call Device to disconnect 
     */
    this.disconnect = function () {
        return comm.disconnect();
    }

    /**
     * Call Device to load Tags propperty in local for polling read values
     */
    this.load = function (data) {
        return comm.load(data);
    }

    /**
     * Call Device to retrun Tags with values
     */
    this.getValues = function () {
        return comm.getValues();
    }

    /**
     * Call Device to get Tag value with Timestamp
     */
    this.getValue = function (id, value) {
        return comm.getValue(id);
    }

    /**
     * Call Device to return current status
     */
    this.getStatus = function () {
        return comm.getStatus();
    }

    /**
     * Call Device to set Tag value
     */
    this.setValue = function (id, value) {
        return comm.setValue(id, value);
    }

    /**
     * Call Device to return browser result Tags/Nodes (only OPCUA)
     */
    this.browse = function (path) {
        return new Promise(function (resolve, reject) {
            if (data.type === DeviceEnum.OPCUA) {
                comm.browse(path).then(function (result) {
                    resolve(result);
                }).catch(function (err) {
                    reject(err);
                });
            } else {
                reject('Browse not supported!');
            }
        });
    }

    /**
     * Call Device to return Tag/Node attribute (only OPCUA)
     */
    this.readNodeAttribute = function(node) {
        return new Promise(function (resolve, reject) {
            if (data.type === DeviceEnum.OPCUA) {
                comm.readAttribute(node).then(function (result) {
                    resolve(result);
                }).catch(function (err) {
                    reject(err);
                });
            } else {
                reject('Read Node attribute not supported!');
            }
        });
    }

    /**
     * Call Device to bind the DAQ store function
     */
    this.bindSaveDaqValue = function (fnc) {
        comm.bindAddDaq(fnc, DEVICE_DAQ_MIN_INTERVAL);
        //return comm.addDaq = fnc;
    }

    /**
     * Call Device to return Tag property
     */
    this.getTagProperty = function (id) {
        return comm.getTagProperty(id);
    }

    /**
     * Bind function to ask project stored property (security)
     */
    this.bindGetProperty = function (fnc) {
        if (data.type === DeviceEnum.OPCUA) {
            comm.bindGetProperty(fnc);
        }
    }

    this.load(data);
}
// with DAQ enabled, interval to save DAQ value anyway !!bigger as DEVICE_POLLING_INTERVAL
with DAQ enabled, interval to save DAQ value anyway !!bigger as DEVICE_POLLING_INTERVAL
with DAQ enabled interval to save DAQ value anyway !!bigger as DEVICE_POLLING_INTERVAL
function Device(data, logger, _events) {
    var property = { id: data.id, name: data.name };        
    var status = DeviceStatusEnum.INIT;                     
    var events = _events;                                   
    var comm;                                               
    var currentCmd = null;                                  
    var deviceCheckStatus = null;                           
    var devicePolling = null;                               
    if (data.type === DeviceEnum.S7) {
        comm = S7client.create(data, logger, events);
    } else if (data.type === DeviceEnum.OPCUA) {
        comm = OpcUAclient.create(data, logger, events);
    } else if (data.type === DeviceEnum.ModbusRTU || data.type === DeviceEnum.ModbusTCP) {
        comm = MODBUSclient.create(data, logger, events);        
    }
    this.start = function () {
        currentCmd = DeviceCmdEnum.START;
        if (status === DeviceStatusEnum.INIT) {
            logger.info(property.name + ': ' + currentCmd);
            var self = this;
            this.checkStatus();
            deviceCheckStatus = setInterval(function () {
                self.checkStatus();
            }, DEVICE_CHECK_STATUS_INTERVAL);
        }
    }
    this.stop = function () {
        return new Promise(function (resolve, reject) {
            currentCmd = DeviceCmdEnum.STOP;
            logger.info(property.name + ': ' + currentCmd);
            if (devicePolling) {
                clearInterval(devicePolling);
                devicePolling = null;
            }
            if (deviceCheckStatus) {
                clearInterval(deviceCheckStatus);
                deviceCheckStatus = null;
            }
            comm.disconnect().then(function () {
                status = DeviceStatusEnum.INIT;
                resolve();
            });
        });
    }
    this.checkStatus = function () {
        if (status === DeviceStatusEnum.INIT && currentCmd === DeviceCmdEnum.START) {
            this.connect().then(function () {
                status = DeviceStatusEnum.IDLE;
            }).catch(function (err) {
            });
        } else if (status === DeviceStatusEnum.IDLE && !comm.isConnected()) {
            status = DeviceStatusEnum.INIT;
            if (devicePolling) {
                clearInterval(devicePolling);
                devicePolling = null;
            }
        }
    }
    this.polling = function () {
        comm.polling();
    }
    this.connect = function () {
        var self = this;
        if (data.type === DeviceEnum.ModbusRTU) {
            comm.init(MODBUSclient.ModbusTypes.RTU);
        } else if (data.type === DeviceEnum.ModbusTCP) {
            comm.init(MODBUSclient.ModbusTypes.TCP);
        }
        return comm.connect().then(function () {
            devicePolling = setInterval(function () {
                self.polling();
            }, DEVICE_POLLING_INTERVAL);
        });
    }
    this.disconnect = function () {
        return comm.disconnect();
    }
    this.load = function (data) {
        return comm.load(data);
    }
    this.getValues = function () {
        return comm.getValues();
    }
    this.getValue = function (id, value) {
        return comm.getValue(id);
    }
    this.getStatus = function () {
        return comm.getStatus();
    }
    this.setValue = function (id, value) {
        return comm.setValue(id, value);
    }
    this.browse = function (path) {
        return new Promise(function (resolve, reject) {
            if (data.type === DeviceEnum.OPCUA) {
                comm.browse(path).then(function (result) {
                    resolve(result);
                }).catch(function (err) {
                    reject(err);
                });
            } else {
                reject('Browse not supported!');
            }
        });
    }
    this.readNodeAttribute = function(node) {
        return new Promise(function (resolve, reject) {
            if (data.type === DeviceEnum.OPCUA) {
                comm.readAttribute(node).then(function (result) {
                    resolve(result);
                }).catch(function (err) {
                    reject(err);
                });
            } else {
                reject('Read Node attribute not supported!');
            }
        });
    }
    this.bindSaveDaqValue = function (fnc) {
        comm.bindAddDaq(fnc, DEVICE_DAQ_MIN_INTERVAL);
    }
    this.getTagProperty = function (id) {
        return comm.getTagProperty(id);
    }
    this.bindGetProperty = function (fnc) {
        if (data.type === DeviceEnum.OPCUA) {
            comm.bindGetProperty(fnc);
        }
    }
    this.load(data);
}
function Device ( data , logger , _events ) { var property = { id : data . id , name : data . name } ; var status = DeviceStatusEnum . INIT ; var events = _events ; var comm ; var currentCmd = null ; var deviceCheckStatus = null ; var devicePolling = null ; if ( data . type === DeviceEnum . S7 ) { comm = S7client . create ( data , logger , events ) ; } else if ( data . type === DeviceEnum . OPCUA ) { comm = OpcUAclient . create ( data , logger , events ) ; } else if ( data . type === DeviceEnum . ModbusRTU || data . type === DeviceEnum . ModbusTCP ) { comm = MODBUSclient . create ( data , logger , events ) ; } this . start = function ( ) { currentCmd = DeviceCmdEnum . START ; if ( status === DeviceStatusEnum . INIT ) { logger . info ( property . name + ': ' + currentCmd ) ; var self = this ; this . checkStatus ( ) ; deviceCheckStatus = setInterval ( function ( ) { self . checkStatus ( ) ; } , DEVICE_CHECK_STATUS_INTERVAL ) ; } } this . stop = function ( ) { return new Promise ( function ( resolve , reject ) { currentCmd = DeviceCmdEnum . STOP ; logger . info ( property . name + ': ' + currentCmd ) ; if ( devicePolling ) { clearInterval ( devicePolling ) ; devicePolling = null ; } if ( deviceCheckStatus ) { clearInterval ( deviceCheckStatus ) ; deviceCheckStatus = null ; } comm . disconnect ( ) . then ( function ( ) { status = DeviceStatusEnum . INIT ; resolve ( ) ; } ) ; } ) ; } this . checkStatus = function ( ) { if ( status === DeviceStatusEnum . INIT && currentCmd === DeviceCmdEnum . START ) { this . connect ( ) . then ( function ( ) { status = DeviceStatusEnum . IDLE ; } ) . catch ( function ( err ) { } ) ; } else if ( status === DeviceStatusEnum . IDLE && ! comm . isConnected ( ) ) { status = DeviceStatusEnum . INIT ; if ( devicePolling ) { clearInterval ( devicePolling ) ; devicePolling = null ; } } } this . polling = function ( ) { comm . polling ( ) ; } this . connect = function ( ) { var self = this ; if ( data . type === DeviceEnum . ModbusRTU ) { comm . init ( MODBUSclient . ModbusTypes . RTU ) ; } else if ( data . type === DeviceEnum . ModbusTCP ) { comm . init ( MODBUSclient . ModbusTypes . TCP ) ; } return comm . connect ( ) . then ( function ( ) { devicePolling = setInterval ( function ( ) { self . polling ( ) ; } , DEVICE_POLLING_INTERVAL ) ; } ) ; } this . disconnect = function ( ) { return comm . disconnect ( ) ; } this . load = function ( data ) { return comm . load ( data ) ; } this . getValues = function ( ) { return comm . getValues ( ) ; } this . getValue = function ( id , value ) { return comm . getValue ( id ) ; } this . getStatus = function ( ) { return comm . getStatus ( ) ; } this . setValue = function ( id , value ) { return comm . setValue ( id , value ) ; } this . browse = function ( path ) { return new Promise ( function ( resolve , reject ) { if ( data . type === DeviceEnum . OPCUA ) { comm . browse ( path ) . then ( function ( result ) { resolve ( result ) ; } ) . catch ( function ( err ) { reject ( err ) ; } ) ; } else { reject ( 'Browse not supported!' ) ; } } ) ; } this . readNodeAttribute = function ( node ) { return new Promise ( function ( resolve , reject ) { if ( data . type === DeviceEnum . OPCUA ) { comm . readAttribute ( node ) . then ( function ( result ) { resolve ( result ) ; } ) . catch ( function ( err ) { reject ( err ) ; } ) ; } else { reject ( 'Read Node attribute not supported!' ) ; } } ) ; } this . bindSaveDaqValue = function ( fnc ) { comm . bindAddDaq ( fnc , DEVICE_DAQ_MIN_INTERVAL ) ; } this . getTagProperty = function ( id ) { return comm . getTagProperty ( id ) ; } this . bindGetProperty = function ( fnc ) { if ( data . type === DeviceEnum . OPCUA ) { comm . bindGetProperty ( fnc ) ; } } this . load ( data ) ; }
with DAQ enabled, interval to save DAQ value anyway !
with DAQ enabled interval to save DAQ value anyway !
// Device property (name, id) // Current status (StateMachine) // Events to commit change to runtime // Interface to OPCUA/S7 Device // Current Command (StateMachine) // TimerInterval to check Device status (connection) // TimerInterval to polling read device value /**
     * Start StateMachine, init and start TimerInterval to check Device status
     */ /**
     * Stop StateMachine, Close Device connection, break all TimerInterval (Device status/polling)
     */ /**
     * Check the Device connection, Reconnect
     */ // devices.woking = null; /**
     * Call Device to polling
     */ /**
     * Call Device to connect and start TimerInterval for read value polling
     */ /**
     * Call Device to disconnect 
     */ /**
     * Call Device to load Tags propperty in local for polling read values
     */ /**
     * Call Device to retrun Tags with values
     */ /**
     * Call Device to get Tag value with Timestamp
     */ /**
     * Call Device to return current status
     */ /**
     * Call Device to set Tag value
     */ /**
     * Call Device to return browser result Tags/Nodes (only OPCUA)
     */ /**
     * Call Device to return Tag/Node attribute (only OPCUA)
     */ /**
     * Call Device to bind the DAQ store function
     */ //return comm.addDaq = fnc; /**
     * Call Device to return Tag property
     */ /**
     * Bind function to ask project stored property (security)
     */