UNPKG

homebridge-s7-plc

Version:

SIEMENS S7 PLC plugin for HomeBridge (https://github.com/homebridge).

545 lines (475 loc) 17.4 kB
var debug = require('debug')('homebridge-S7-PLC') //debug messages ->https://github.com/visionmedia/debug var debugLightDimm = require('debug')('homebridge-S7-PLC_LightDimm') var debugLightBulb = require('debug')('homebridge-S7-PLC_LightBulb') var debugSensor = require('debug')('homebridge-S7-PLC_Sensor') var Service, Characteristic; var snap7 = require('node-snap7'); var S7accessory = { "S7_LightBulb": LightBulb, "S7_LightDimm": LightDimm, "S7_Sensor" : Sensor }//this var is used to have a unique constructor for accessories instanciation in platform //Exports module.exports = function(homebridge) { // Service and Characteristic from hap-nodejs/lib/gen/HomeKitTypes.js Service = homebridge.hap.Service; Characteristic = homebridge.hap.Characteristic; homebridge.registerPlatform('homebridge-s7-plc', 'S7', S7Platform); homebridge.registerAccessory('homebridge-s7-plc', 'S7_LightDimm', LightDimm, true); homebridge.registerAccessory('homebridge-s7-plc', 'S7_LightBulb', LightBulb, true); homebridge.registerAccessory('homebridge-s7-plc', 'S7_Sensor', Sensor, true); } //Platform definitions //S7 //config.json: // "platforms": [ // { // "platform": "S7", // "IP": "10.10.10.10", // "RACK": 0, // "SLOT": 2, // "accessories": [] // } // ] function S7Platform(log, config) { //initialize this.log = log; this.config = config; this.ip = this.config.IP; this.rack = this.config.RACK; this.slot = this.config.SLOT; this.S7Client = new snap7.S7Client(); //PLC connection synchonousely... this.log(">> S7Client connecting to %s (%s:%s)", this.ip, this.rack , this.slot); this.S7Client.ConnectTo(this.ip, this.rack , this.slot); this.connecting = false; } S7Platform.prototype = { //Accessories retrieval accessories: function(callback) { var log = this.log; debug('Fetching S7 devices...'); //For each device, create an accessory! var foundAccessories = this.config.accessories; //create array of accessories var platformAccessories = []; for (var i = 0; i < foundAccessories.length; i++) { debug('Parsing accessory ' + i + ' of ' + foundAccessories.length); this.log('Pushing new ' + foundAccessories[i].accessory + ' device: ' + foundAccessories[i].name); //Call accessoryConstruction var accessory = new S7accessory[foundAccessories[i].accessory](this, foundAccessories[i]); debug('Creating ' + accessory.name + ' accessory ...'); platformAccessories.push(accessory); } this.log(platformAccessories.length + ' accessories created'); callback(platformAccessories); }, //PLC connection check function S7ClientReconnect: function() { var log = this.log; var S7Client = this.S7Client; var ip = this.ip; var rack = this.rack; var slot = this.slot; var connecting = this.connecting; if (!S7Client.Connected()) { log("S7ClientReconnect: >> S7Client connecting to %s (%s:%s) connecting=%s", ip, rack, slot, connecting); if (!connecting) { this.connecting = true; //PLC connection asynchonousely... S7Client.ConnectTo(ip, rack, slot, function(err) { if(err) { log('S7ClientReconnect: >> Connection failed. Code #' + err + ' - ' + S7Client.ErrorText(err)); log("S7ClientReconnect: >> S7Client connecting=%s", connecting); } else { log("S7ClientReconnect: connected to %s (%s:%s)", ip, rack, slot); } this.connecting = false; }); } } else { debug("S7Client already connected to %s (%s:%s)", ip, rack, slot); } } } //Accessories definitions //LightBulb //config.json: /* { "accessory": "S7_LightBulb", //Type "name": "Salon", //Name "descrition": "Lumière du salon", //Description "DB": 1, //DB number "Byte" : 0, //Offset in the DB "ReadBitState" : 1 //Bit position of STATE status "WriteBitOff" : 2, //Bit position of OFF command "WriteBitOn" : 3 //Bit position of ON command } */ //LightBulb function function LightBulb(platform, config) { this.FirmwareRevision = '0.0.1'; this.platform = platform; this.log = platform.log; this.name = config.name; this.db = config.DB; this.dbbyte = config.Byte; this.dbbiton = config.WriteBitOn; this.dbbitoff = config.WriteBitOff; this.dbbitstate = config.ReadBitState; this.buf = Buffer.alloc(2); this.state = 0; debugLightBulb("Starting a S7_Lightbulb Service '" + this.name + "' on DB%d.DBB%d", this.db, this.dbbyte); } //LightBulb prototype LightBulb.prototype = { setPowerOn: function(powerOn, callback) { //LightBulb send PLC commands ON/OFF or value(%) var log = this.log; var platform = this.platform; var S7Client = this.platform.S7Client; var buf = this.buf; var db = this.db; var dbbyte = this.dbbyte; var dbbiton = this.dbbiton; var dbbitoff = this.dbbitoff; var dbbit = 0; var state = this.state; debugLightBulb("setPowerOn: START"); //check PLC connection platform.S7ClientReconnect(); //Set the correct Bit for the operation if (powerOn) { dbbit = dbbiton; state=1; } else { dbbit = dbbitoff; state=0; } buf[0] = 1; // Write single Bit to DB asynchonousely... S7Client.WriteArea(S7Client.S7AreaDB, db, ((dbbyte*8) + dbbit), 1, S7Client.S7WLBit, buf, function(err) { if(err) { log('setPowerOn: >> DBWrite failed. Code #' + err + ' - ' + S7Client.ErrorText(err)); S7Client.Disconnect(); callback(err); } else { log("setPowerOn: Set power state to %s. Set bit DB%d.DBX%d.%d", state, db, dbbyte, dbbit); callback(null); } }); debugLightBulb("setPowerOn: END"); }, getPowerOn: function(callback) { //LightBulb get PLC status ON/OFF var log = this.log; var platform = this.platform; var S7Client = this.platform.S7Client; var db = this.db; var dbbyte = this.dbbyte; var dbbit = this.dbbitstate; var buf = this.buf; var state = this.state; debugLightBulb("getPowerOn: START"); //check PLC connection platform.S7ClientReconnect(); if (S7Client.Connected()) { // Read one bit from PLC DB asynchonousely... S7Client.ReadArea(S7Client.S7AreaDB, db, ((dbbyte*8) + dbbit), 1, S7Client.S7WLBit, function(err, res) { if(err) { log('getPowerOn: >> DBRead failed. Code #' + err + ' - ' + S7Client.ErrorText(err)); S7Client.Disconnect(); state = 0; callback(err, state); } else { if (res[0]) { state = 1; debugLightBulb("getPowerOn: Power is on"); } else { state = 0; debugLightBulb("getPowerOn: Power is off"); } debugLightBulb("getPowerOn: DB%d.DBX%d.%d: bitvalue=%d state=%d", db, dbbyte, dbbit, res[0], state); callback(null, state); } }); debugLightBulb("getPowerOn: END"); } else { callback(new Error('PLC not connected'), false); } }, getServices: function() { var informationService = new Service.AccessoryInformation(); informationService .setCharacteristic(Characteristic.Manufacturer, 'BMA') .setCharacteristic(Characteristic.Model, 'S7-Sensor') .setCharacteristic(Characteristic.SerialNumber, '085-250-085') .setCharacteristic(Characteristic.FirmwareRevision, this.FirmwareRevision); var lightbulbService = new Service.Lightbulb(this.name); lightbulbService .getCharacteristic(Characteristic.On) .on('get', this.getPowerOn.bind(this)) .on('set', this.setPowerOn.bind(this)); return [lightbulbService,informationService]; } } //LightDimm //config.json: /* { "accessory": "S7_LightDimm", //Type "name": "Salon", //Name "descrition": "Lumière du salon", //Description "DB": 1, //DB number "Byte" : 0 //Offset in the DB } */ //LightDimm function function LightDimm(platform, config) { this.FirmwareRevision = '0.0.1'; this.platform = platform; this.log = platform.log; this.name = config.name; this.db = config.DB; this.dbbyte = config.Byte; this.buf1 = Buffer.alloc(2); this.buf2 = Buffer.alloc(2); this.BrightnessVal = 0; debugLightDimm("Starting a s7_LightDimm Service '" + this.name + "' on DB%d.DBB%d", this.db, this.dbbyte); } //LightDimm prototype LightDimm.prototype = { setPowerOn: function(powerOn, callback) { //LightDimm send PLC commands ON/OFF var log = this.log; var platform = this.platform; var S7Client = this.platform.S7Client; var buf = this.buf1; var db = this.db; var dbbyte = this.dbbyte; debugLightDimm("setPowerOn: START"); //check PLC connection platform.S7ClientReconnect(); debugLightDimm("setPowerOn: powerOn=%d BrightnessVal=%d",powerOn,this.BrightnessVal); if (powerOn) { if (this.BrightnessVal>0) buf[0] = this.BrightnessVal; else buf[0] = 100; } else buf[0] = 0; // Write to DB asynchonousely... S7Client.DBWrite(db, dbbyte, 1, buf, function(err) { if(err) { log('setPowerOn: >> DBWrite failed. Code #' + err + ' - ' + S7Client.ErrorText(err)); S7Client.Disconnect(); callback(err); } else { log("setPowerOn: Set power BrightnessVal to %s. Set word DB%d.DBW%d", buf[0], db, dbbyte); callback(null); } }); debugLightDimm("setPowerOn: END"); }, getPowerOn: function(callback) { //LightDimm get PLC status ON/OFF var log = this.log; var platform = this.platform; var S7Client = this.platform.S7Client; var db = this.db; var dbbyte = this.dbbyte; var buf = this.buf1; var me = this; debugLightDimm("getPowerOn: START"); //check PLC connection platform.S7ClientReconnect(); if (S7Client.Connected()) { // Read one word from PLC DB asynchonousely... S7Client.ReadArea(S7Client.S7AreaDB, db, dbbyte, 1, S7Client.S7WLByte, function(err, res) { if(err) { log('getPowerOn: >> DBRead failed. Code #' + err + ' - ' + S7Client.ErrorText(err)); S7Client.Disconnect(); callback(err, false); } else { debugLightDimm("getPowerOn: DB%d.DBW%d: %d", db, dbbyte, res[0]); me.BrightnessVal=res[0]; callback(null, res[0]!=0); } }); debugLightDimm("getPowerOn: END"); } else { callback(new Error('PLC not connected'), false); } }, setBrightness: function(brightness, callback) { //LightDimm send PLC commands value(%) var log = this.log; var platform = this.platform; var S7Client = this.platform.S7Client; var ip = this.ip; var buf = this.buf2; var db = this.db; var dbbyte = this.dbbyte; debugLightDimm("setbrightness: START"); this.BrightnessVal = brightness; //check PLC connection platform.S7ClientReconnect(); debugLightDimm("setbrightness: brightness=%d",brightness); buf[0] = brightness; // Write to DB asynchonousely... S7Client.DBWrite(db, dbbyte, 1, buf, function(err) { if(err) { log('setbrightness: >> DBWrite failed. Code #' + err + ' - ' + S7Client.ErrorText(err)); S7Client.Disconnect(); callback(err); } else { log("setbrightness: Set power BrightnessVal to %s. Set word DB%d.DBW%d", buf[0], db, dbbyte); callback(null); } }); debugLightDimm("setbrightness: END"); }, getBrightness: function(callback) { //LightDimm get PLC status (%) var log = this.log; var platform = this.platform; var S7Client = this.platform.S7Client; var db = this.db; var dbbyte = this.dbbyte; var buf = this.buf2; var me = this; debugLightDimm("getbrightness: START"); //check PLC connection platform.S7ClientReconnect(); if (S7Client.Connected()) { // Read one word from PLC DB asynchonousely... S7Client.ReadArea(S7Client.S7AreaDB, db, dbbyte, 1, S7Client.S7WLByte, function(err, res) { if(err) { log('getbrightness: >> DBRead failed. Code #' + err + ' - ' + S7Client.ErrorText(err)); S7Client.Disconnect(); callback(err, this.BrightnessVal); } else { debugLightDimm("getbrightness: DB%d.DBW%d: %d", db, dbbyte, res[0]); me.BrightnessVal=res[0]; callback(null, res[0]); } }); debugLightDimm("getbrightness: END"); } else { callback(new Error('PLC not connected'), 0); } }, getServices: function() { var informationService = new Service.AccessoryInformation(); informationService .setCharacteristic(Characteristic.Manufacturer, 'BMA') .setCharacteristic(Characteristic.Model, 'S7-Sensor') .setCharacteristic(Characteristic.SerialNumber, '085-250-085') .setCharacteristic(Characteristic.FirmwareRevision, this.FirmwareRevision); var LightDimmService = new Service.Lightbulb(this.name); LightDimmService .getCharacteristic(Characteristic.Brightness) .on('get', this.getBrightness.bind(this)) .on('set', this.setBrightness.bind(this)) .setProps({ minValue: 20, maxValue: 100, minStep: 1 }); LightDimmService .getCharacteristic(Characteristic.On) .on('get', this.getPowerOn.bind(this)) .on('set', this.setPowerOn.bind(this)); return [LightDimmService,informationService]; } } //Sensor //config.json: /* { "accessory": "s7_sensor", //Type "PLC_IP_Adr": "1.1.1.1", //PLC IP address "name": "Extérieure", //Name "descrition": "Température extérieure", //Description "DB": 1, //DB number "Byte" : 0 //Offset in the DB } */ //Sensor function function Sensor(platform, config) { this.FirmwareRevision = '0.0.1'; this.platform = platform; this.log = platform.log; this.name = config.name; this.db = config.DB; this.dbbyte = config.Byte; this.value = 0.0; debugSensor("Starting a S7_Sensor Service '" + this.name + "' on DB%d.DBD%d", this.db, this.dbbyte); } //Sensor prototype Sensor.prototype = { getCurrentValue: function(callback) { var log = this.log; var platform = this.platform; var S7Client = this.platform.S7Client; var db = this.db; var dbbyte = this.dbbyte; var value= this.value; debugSensor("getCurrentValue: START"); //check PLC connection platform.S7ClientReconnect(); if (S7Client.Connected()) { // Read one real from DB asynchonousely... S7Client.ReadArea(S7Client.S7AreaDB, db, dbbyte, 1, S7Client.S7WLReal, function(err, res) { if(err) { log(' >> DBRead failed (DB' + db + '.DBD' + dbbyte + '):. Code #' + err + ' - ' + S7Client.ErrorText(err)); S7Client.Disconnect(); value = 0.0; callback(err, null); } else { debugSensor("getCurrentValue: DB%d.DBD%d: %f", db, dbbyte, res.readFloatBE(0)); value = res.readFloatBE(0); callback(null, value); } }); debugSensor("getCurrentValue: END"); } else { callback(new Error('PLC not connected'), this.minValue); } }, getServices: function() { var informationService = new Service.AccessoryInformation(); informationService .setCharacteristic(Characteristic.Manufacturer, 'BMA') .setCharacteristic(Characteristic.Model, 'S7-Sensor') .setCharacteristic(Characteristic.SerialNumber, '085-250-085') .setCharacteristic(Characteristic.FirmwareRevision, this.FirmwareRevision); var sensorService = new Service.TemperatureSensor(this.name); sensorService .getCharacteristic(Characteristic.CurrentTemperature) .on('get', this.getCurrentValue.bind(this)) .setProps({ minValue: -50, maxValue: 50, minStep: 0.1 }); return [sensorService,informationService]; } }