UNPKG

prisme-flow

Version:

prisme platform flow engine

331 lines (273 loc) 7.77 kB
/** * Created by prisme.io on 09/06/2017. */ module.exports = function (RED) { 'use strict' var util = require('util') var nodes7 = require('nodes7') var EventEmitter = require('events').EventEmitter // ---------- S7 Endpoint ---------- function createTranslationTable (vars) { var res = {} vars.forEach(function (elm) { res[elm.name] = elm.addr }) return res } function generateStatus (status, val) { var obj if (typeof val !== 'string' && typeof val !== 'number' && typeof val !== 'boolean') { val = RED._('online') } switch (status) { case 'online': obj = { fill: 'green', shape: 'dot', text: val.toString() } break case 'badvalues': obj = { fill: 'yellow', shape: 'dot', text: RED._('failure') } break case 'offline': obj = { fill: 'red', shape: 'dot', text: RED._('offline') } break default: obj = { fill: 'grey', shape: 'dot', text: RED._('unknown') } } return obj } function S7Endpoint (config) { EventEmitter.call(this) var node = this var oldValues = {} var status var readInProgress = false var readDeferred = false var vars = config.vartable var isVerbose = !!RED.settings.get('verbose') node.writeInProgress = false node.writeQueue = [] if (typeof vars === 'string') { vars = JSON.parse(vars) } RED.nodes.createNode(this, config) // avoids warnings when we have a lot of S7In nodes this.setMaxListeners(0) node._vars = createTranslationTable(vars) node._conn = new nodes7({ silent: !isVerbose, debug: isVerbose }) node._conn.globalTimeout = parseInt(config.timeout) || 1500 node.getStatus = function getStatus () { return status } node.writeVar = function writeVar (obj) { node.writeQueue.push(obj) if (!node.writeInProgress) { writeNext() } } function onWritten (err) { node.writeInProgress = false writeNext() if (err) { manageStatus('badvalues') node.error(RED._('Failure (Bad values)')) return } manageStatus('online') } function writeNext () { var nextElm = node.writeQueue.shift() if (nextElm) { node._conn.writeItems(nextElm.name, nextElm.val, onWritten) node.writeInProgress = true } } function manageStatus (newStatus) { if (status == newStatus) return status = newStatus node.emit('__STATUS__', { status: status }) } function cycleCallback (err, values) { readInProgress = false if (readDeferred) { doCycle() readDeferred = false } if (err) { manageStatus('badvalues') node.error(RED._('Failure (Bad values)')) return } manageStatus('online') var changed = false node.emit('__ALL__', values) Object.keys(values).forEach(function (key) { if (oldValues[key] !== values[key]) { changed = true node.emit(key, values[key]) node.emit('__CHANGED__', {key: key, value: values[key]}) oldValues[key] = values[key] } }) if (changed) node.emit('__ALL_CHANGED__', values) } function doCycle () { if (!readInProgress) { node._conn.readAllItems(cycleCallback) readInProgress = true } else { readDeferred = true } } function onConnect (err) { if (err) { manageStatus('offline') node.error(RED._('Error connecting to PLC:') + err.toString()) return } manageStatus('online') node._conn.setTranslationCB(function (tag) { return node._vars[tag] }) node._conn.addItems(Object.keys(node._vars)) node._td = setInterval(doCycle, config.cycletime) } node.on('close', function (done) { clearInterval(node._td) node._conn.dropConnection(function () { done() }) }) manageStatus('offline') node._conn.initiateConnection({ host: config.address, port: config.port, rack: config.rack, slot: config.slot }, onConnect) } RED.nodes.registerType('s7 endpoint', S7Endpoint) // ---------- S7 In ---------- function S7In (config) { var node = this var statusVal RED.nodes.createNode(this, config) node.endpoint = RED.nodes.getNode(config.endpoint) if (!node.endpoint) { return node.error(RED._('Missing configuration')) } function sendMsg (data, key, status) { if (key === undefined) key = '' var msg = { payload: data, topic: key } statusVal = status !== undefined ? status : data node.send(msg) node.status(generateStatus(node.endpoint.getStatus(), statusVal)) } function onChanged (variable) { sendMsg(variable.value, variable.key, null) } function onDataSplit (data) { Object.keys(data).forEach(function (key) { sendMsg(data[key], key, null) }) } function onData (data) { sendMsg(data, config.mode == 'single' ? config.variable : '') } function onDataSelect (data) { onData(data[config.variable]) } function onEndpointStatus (s) { node.status(generateStatus(s.status, statusVal)) } node.endpoint.on('__STATUS__', onEndpointStatus) if (config.diff) { switch (config.mode) { case 'all-split': node.endpoint.on('__CHANGED__', onChanged) break case 'single': node.endpoint.on(config.variable, onData) break case 'all': default: node.endpoint.on('__ALL_CHANGED__', onData) } } else { switch (config.mode) { case 'all-split': node.endpoint.on('__ALL__', onDataSplit) break case 'single': node.endpoint.on('__ALL__', onDataSelect) break case 'all': default: node.endpoint.on('__ALL__', onData) } } node.on('close', function (done) { node.endpoint.removeListener('__ALL__', onDataSelect) node.endpoint.removeListener('__ALL__', onDataSplit) node.endpoint.removeListener('__ALL__', onData) node.endpoint.removeListener('__ALL_CHANGED__', onData) node.endpoint.removeListener('__CHANGED__', onChanged) node.endpoint.removeListener('__STATUS__', onEndpointStatus) node.endpoint.removeListener(config.variable, onData) done() }) } RED.nodes.registerType('s7 in', S7In) // ---------- S7 Out ---------- function S7Out (config) { var node = this var statusVal RED.nodes.createNode(this, config) node.endpoint = RED.nodes.getNode(config.endpoint) if (!node.endpoint) { return node.error(RED._('Missing configuration')) } function onEndpointStatus (s) { node.status(generateStatus(s.status, statusVal)) } function onNewMsg (msg) { var writeObj = { name: config.variable || msg.variable, val: msg.payload } if (!writeObj.name) return statusVal = writeObj.val node.endpoint.writeVar(writeObj) node.status(generateStatus(node.endpoint.getStatus(), statusVal)) } node.on('input', onNewMsg) node.endpoint.on('__STATUS__', onEndpointStatus) node.on('close', function (done) { node.endpoint.removeListener('__STATUS__', onEndpointStatus) done() }) } RED.nodes.registerType('s7 out', S7Out) }