UNPKG

homebridge-logo-platform

Version:
527 lines (460 loc) 17.6 kB
let snap7 = require('napi-snap7'); import { ErrorNumber } from "./error"; export enum Area { S7AreaPE = 0x81, S7AreaPA = 0x82, S7AreaMK = 0x83, S7AreaDB = 0x84, S7AreaCT = 0x1C, S7AreaTM = 0x1D } export enum WordLen { S7WLBit = 0x01, S7WLByte = 0x02, S7WLChar = 0x03, S7WLWord = 0x04, S7WLInt = 0x05, S7WLDWord = 0x06, S7WLDInt = 0x07, S7WLReal = 0x08, S7WLCounter = 0x1C, S7WLTimer = 0x1D } export class LogoAddress { constructor( public addr: number, public bit: number, public wLen: WordLen ) {} } export class Snap7Logo { public type: string = "0BA7"; public ipAddr: string = ""; public local_TSAP: number = 0x2000; public remote_TSAP: number = 0x2000; public db: number = 1; public debugMsgLog: number = 0; public log: Function; public retryCnt: number; public s7client: any; constructor( type: string, ipAddr: string, local_TSAP: number, remote_TSAP: number, debug: number, logFunction: any, retrys: number ) { this.type = type; this.ipAddr = ipAddr; this.local_TSAP = local_TSAP; this.remote_TSAP = remote_TSAP; this.debugMsgLog = debug; this.log = logFunction; this.retryCnt = retrys; this.s7client = new snap7.S7Client(); this.s7client.SetConnectionParams(this.ipAddr, this.local_TSAP, this.remote_TSAP); } ReadLogo(item: string, callBack: (value: number) => any) { this.ConnectS7(this.s7client, this.debugMsgLog, this.retryCnt, (success: Boolean) => { if(success == false) { if (this.debugMsgLog == 1) { this.log('ReadLogo() - Connection failed.'); } callBack(ErrorNumber.noData); return ErrorNumber.noData; } var target = this.getAddressAndBit(item, this.type); this.DBReadS7(this.s7client, this.db, target, this.debugMsgLog, this.retryCnt, (success: number) => { if (success == ErrorNumber.noData) { callBack(ErrorNumber.noData); } else { if (success > ErrorNumber.maxPositivNumber) { success = success - ErrorNumber.max16BitNumber; } callBack(success); } }); }); } WriteLogo(item: string, value: number) { this.ConnectS7(this.s7client, this.debugMsgLog, this.retryCnt, (success: Boolean) => { if(success == false) { if (this.debugMsgLog == 1) { this.log('WriteLogo() - Connection failed.'); } return ErrorNumber.noData; } var target = this.getAddressAndBit(item, this.type); var buffer_on; if (target.wLen == WordLen.S7WLBit) { buffer_on = Buffer.from([value << target.bit]); } if (target.wLen == WordLen.S7WLByte) { buffer_on = Buffer.from([value]); } if (target.wLen == WordLen.S7WLWord) { buffer_on = Buffer.from([((value & 0b1111111100000000) >> 8), (value & 0b0000000011111111)]); } if (target.wLen == WordLen.S7WLDWord) { buffer_on = Buffer.from([((value & 0b11111111000000000000000000000000) >> 24), ((value & 0b00000000111111110000000000000000) >> 16), ((value & 0b00000000000000001111111100000000) >> 8), (value & 0b00000000000000000000000011111111)]); } this.DBWriteS7(this.s7client, this.db, target, this.debugMsgLog, this.retryCnt, buffer_on, (success: Boolean) => { if(!success) { return ErrorNumber.noData; } }); }); } ConnectS7(s7client: any, debugLog: number, retryCount: number, callBack?: (success: Boolean) => any) { if (retryCount == 0) { if (debugLog == 1) { this.log('ConnectS7() - Retry counter reached max value'); } if (callBack) { callBack(false); } return false; } if (s7client.GetConnected() != true) { s7client.Disconnect(); retryCount = retryCount - 1; let err = s7client.Connect(); if(err == ErrorNumber.noConnection) { if ((debugLog == 1) && (retryCount == 1)) { this.log('ConnectS7() - Connection failed. Retrying. Code #' + err + ' - ' + s7client.ErrorText(err)); } if ((debugLog == 1) && (retryCount > 1)) { this.log('ConnectS7() - Connection failed. Retrying. (%i)', retryCount); } s7client.Disconnect(); sleep(100).then(() => { this.ConnectS7(s7client, debugLog, retryCount, callBack); }); } else { if (callBack) { callBack(true); } } } else { if (callBack) { callBack(true); } } return true; } DisconnectS7() { if (this.s7client.GetConnected() == true) { this.s7client.Disconnect(); if (this.debugMsgLog == 1) { this.log('DisconnectS7() - Disconnect LOGO!'); } } } ReadAreaS7(s7client: any, db: number, target: LogoAddress, debugLog: number, retryCount: number, callBack: (success: number) => any) { if (retryCount == 0) { if (debugLog == 1) { this.log('ReadS7() - Retry counter reached max value'); } callBack(ErrorNumber.noData); return ErrorNumber.noData; } retryCount = retryCount - 1; // Area, DBNumber, Start, Amount, WordLen s7client.ReadArea(Area.S7AreaDB, db, target.addr, 1, 0x02, (err, data) => { if(err) { if ((debugLog == 1) && (retryCount == 1)) { this.log('ReadS7() - ReadArea failed. Code #' + err + ' - ' + this.s7client.ErrorText(err)); } if ((debugLog == 1) && (retryCount > 1)) { this.log('ReadS7() - ReadArea failed. Retrying. (%i)', retryCount); } sleep(100).then(() => { this.ReadAreaS7(s7client, db, target, debugLog, retryCount, callBack); }); } else { var buffer = Buffer.from(data); if (target.wLen == WordLen.S7WLBit) { callBack((buffer[0] >> target.bit) & 1); } if (target.wLen == WordLen.S7WLByte) { callBack(buffer[0]); } if (target.wLen == WordLen.S7WLWord) { callBack( (buffer[0] << 8) | buffer[1] ); } if (target.wLen == WordLen.S7WLDWord) { callBack( (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3] ); } callBack(ErrorNumber.noData); } }); } DBReadS7(s7client: any, db: number, target: LogoAddress, debugLog: number, retryCount: number, callBack: (success: number) => any) { if (retryCount == 0) { if (debugLog == 1) { this.log('ReadS7() - Retry counter reached max value'); } callBack(ErrorNumber.noData); return ErrorNumber.noData; } retryCount = retryCount - 1; let leng = this.getWordSize(target.wLen); s7client.DBRead(db, target.addr, leng, (err, data) => { if(err) { if ((debugLog == 1) && (retryCount == 1)) { this.log('ReadS7() - DBRead failed. Code #' + err + ' - ' + this.s7client.ErrorText(err)); } if ((debugLog == 1) && (retryCount > 1)) { this.log('ReadS7() - DBRead failed. Retrying. (%i)', retryCount); } sleep(100).then(() => { this.DBReadS7(s7client, db, target, debugLog, retryCount, callBack); }); } else { var buffer = Buffer.from(data); if (target.wLen == WordLen.S7WLBit) { // this.log('Bit: ', (buffer[0] >> target.bit) & 1); callBack((buffer[0] >> target.bit) & 1); } if (target.wLen == WordLen.S7WLByte) { // this.log('Byte: ', buffer[0]); callBack(buffer[0]); } if (target.wLen == WordLen.S7WLWord) { // this.log('Word: ', (buffer[0] << 8) | buffer[1]); callBack( (buffer[0] << 8) | buffer[1] ); } if (target.wLen == WordLen.S7WLDWord) { // this.log('DWord: ', (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]); callBack( (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3] ); } // callBack(ErrorNumber.noData); } }); } WriteAreaS7(s7client: any, db: number, target: LogoAddress, debugLog: number, retryCount: number, buffer: Buffer, callBack: (success: Boolean) => any) { if (retryCount == 0) { if (debugLog == 1) { this.log('WriteS7() - Retry counter reached max value'); } if (callBack) { callBack(false); } return ErrorNumber.noData; } retryCount = retryCount - 1; // Area, DBNumber, Start, Amount, WordLen, Buffer s7client.WriteArea(Area.S7AreaDB, db, target.addr, 1, 0x02, buffer, (err) => { if(err) { if ((debugLog == 1) && (retryCount == 1)) { this.log('WriteS7() - DBWrite failed. Code #' + err + ' - ' + s7client.ErrorText(err)); } if ((debugLog == 1) && (retryCount > 1)) { this.log('WriteS7() - DBWrite failed. Retrying. (%i)', retryCount); } sleep(100).then(() => { this.WriteAreaS7(s7client, db, target, debugLog, retryCount, buffer, callBack); }); } if (callBack) { callBack(true); } }); } DBWriteS7(s7client: any, db: number, target: LogoAddress, debugLog: number, retryCount: number, buffer: Buffer, callBack: (success: Boolean) => any) { if (retryCount == 0) { if (debugLog == 1) { this.log('WriteS7() - Retry counter reached max value'); } if (callBack) { callBack(false); } return ErrorNumber.noData; } retryCount = retryCount - 1; let leng = this.getWordSize(target.wLen); s7client.DBWrite(db, target.addr, leng, buffer, (err) => { if(err) { if ((debugLog == 1) && (retryCount == 1)) { this.log('WriteS7() - DBWrite failed. Code #' + err + ' - ' + s7client.ErrorText(err)); } if ((debugLog == 1) && (retryCount > 1)) { this.log('WriteS7() - DBWrite failed. Retrying. (%i)', retryCount); } sleep(100).then(() => { this.DBWriteS7(s7client, db, target, debugLog, retryCount, buffer, callBack); }); } if (callBack) { callBack(true); } }); } getAddressAndBit(name: string, target_type: string): LogoAddress { if (name.match("AI[0-9]{1,2}")) { var num = parseInt(name.replace("AI", ""), 10) if (target_type == "0BA7") { return Snap7Logo.calculateWord(926, num); } else { return Snap7Logo.calculateWord(1032, num); } } if (name.match("AQ[0-9]{1,2}")) { var num = parseInt(name.replace("AQ", ""), 10) if (target_type == "0BA7") { return Snap7Logo.calculateWord(944, num); } else { return Snap7Logo.calculateWord(1072, num); } } if (name.match("AM[0-9]{1,2}")) { var num = parseInt(name.replace("AM", ""), 10) if (target_type == "0BA7") { return Snap7Logo.calculateWord(952, num); } else { return Snap7Logo.calculateWord(1118, num); } } if (name.match("I[0-9]{1,2}")) { var num = parseInt(name.replace("I", ""), 10) if (target_type == "0BA7") { return Snap7Logo.calculateBit(923, num); } else { return Snap7Logo.calculateBit(1024, num); } } if (name.match("Q[0-9]{1,2}")) { var num = parseInt(name.replace("Q", ""), 10) if (target_type == "0BA7") { return Snap7Logo.calculateBit(942, num); } else { return Snap7Logo.calculateBit(1064, num); } } if (name.match("M[0-9]{1,2}")) { var num = parseInt(name.replace("M", ""), 10) if (target_type == "0BA7") { return Snap7Logo.calculateBit(948, num); } else { return Snap7Logo.calculateBit(1104, num); } } if (name.match("V[0-9]{1,4}\.[0-7]{1}")) { var str = name.replace("V", ""); var a = parseInt(str.split(".", 2)[0], 10); var b = parseInt(str.split(".", 2)[1], 10); return new LogoAddress(a, b, WordLen.S7WLBit); } if (name.match("VB[0-9]{1,4}")) { var num = parseInt(name.replace("VB", ""), 10) return new LogoAddress(num, 0, WordLen.S7WLByte); } if (name.match("VW[0-9]{1,4}")) { var num = parseInt(name.replace("VW", ""), 10) return new LogoAddress(num, 0, WordLen.S7WLWord); } if (name.match("VD[0-9]{1,4}")) { var num = parseInt(name.replace("VD", ""), 10) return new LogoAddress(num, 0, WordLen.S7WLDWord); } return new LogoAddress(0, 0, WordLen.S7WLBit); } isValidLogoAddress(name: string): boolean { if (name.match("AI[0-9]{1,2}")) { return true; } if (name.match("AQ[0-9]{1,2}")) { return true; } if (name.match("AM[0-9]{1,2}")) { return true; } if (name.match("I[0-9]{1,2}")) { return true; } if (name.match("Q[0-9]{1,2}")) { return true; } if (name.match("M[0-9]{1,2}")) { return true; } if (name.match("V[0-9]{1,4}\.[0-7]{1}")) { return true; } if (name.match("VB[0-9]{1,4}")) { return true; } if (name.match("VW[0-9]{1,4}")) { return true; } if (name.match("VD[0-9]{1,4}")) { return true; } return false; } isAnalogLogoAddress(name: string): boolean { if (name.match("AI[0-9]{1,2}")) { return true; } if (name.match("AQ[0-9]{1,2}")) { return true; } if (name.match("AM[0-9]{1,2}")) { return true; } if (name.match("I[0-9]{1,2}")) { return false; } if (name.match("Q[0-9]{1,2}")) { return false; } if (name.match("M[0-9]{1,2}")) { return false; } if (name.match("V[0-9]{1,4}\.[0-7]{1}")) { return false; } if (name.match("VB[0-9]{1,4}")) { return true; } if (name.match("VW[0-9]{1,4}")) { return true; } if (name.match("VD[0-9]{1,4}")) { return true; } return false; } getWordSize(wordLen: Number) { switch (wordLen) { case WordLen.S7WLBit: case WordLen.S7WLByte: return 1; case WordLen.S7WLWord: case WordLen.S7WLCounter: case WordLen.S7WLTimer: return 2; case WordLen.S7WLDWord: case WordLen.S7WLReal: return 4; default: return 0; } } static calculateBit(base: number, num: number) { var x = Math.floor((num - 1) / 8); var y = 8 * (x + 1); var addr = base + x; var bit = 7 - (y - num); return new LogoAddress(addr, bit, WordLen.S7WLBit); } static calculateWord(base: number, num: number) { var addr = base + ((num - 1) * 2); return new LogoAddress(addr, 0, WordLen.S7WLWord); } } const sleep = (milliseconds: number) => { return new Promise(resolve => setTimeout(resolve, milliseconds)) }