iobroker.enocean
Version:
Connects EnOcean devices via USB/Serial devices with TCM300 Chips
1,530 lines (1,365 loc) • 56 kB
JavaScript
'use strict';
const RadioTelegram = require('./ESP3Packet').RadioTelegram;
const RadioTelegram_ERP2 = require('./ESP3Packet').RadioTelegram_ERP2;
const ResponseTelegram = require('./ESP3Packet').ResponseTelegram;
const MSCTelegram = require('./ESP3Packet').MSCTelegram;
const OneBSTeachIn = require('./ESP3Packet').OneBSTeachIn;
const FourBSTeachIn = require('./ESP3Packet').FourBSTeachIn;
const UTETeachIn = require('./ESP3Packet').UTETeachIn;
const EventTelegram = require('./ESP3Packet').EventTelegram;
const jsonLogic = require('json-logic-js');
const ByteArray = require('./byte_array');
const Enocean_manufacturer = require('../definitions/manufacturer_list.json');
const EEPList = require('../definitions/EEPinclude');
const eltakoDevices = require('../definitions/eltako').mscTelegrams;
const devices = require('../definitions/devices.js');
const objDef = require('../definitions/object_definitions').objDef;
const OneBS = 213;
const FourBS = 165;
const RPS = 246;
const UTE = 212;
const MSC = 209;
// const SmartACK = 198;
const VLD = 210;
class handleType1 {
/**
* RADIO_ERP1
* @param {Object} that
* @param {Object} ESP3Packet
*/
constructor(that, ESP3Packet) {
this.adapter = that;
this.info = that.log.info;
this.telegram = new RadioTelegram(ESP3Packet);
this.senderID = this.telegram.senderID;
// this.tType = this.telegram.type;
this.repeaterCount = this.telegram.repeaterCount;
this.rssi = ESP3Packet.optionalData['5'];
//bind class functions to context of constructor
this.main.bind(this);
this.adapter.log.debug('Message for ID ' + this.senderID + ' has been received. It was repeated ' + this.repeaterCount + ' times.');
this.main();
}
async main() {
//get device object
const dev = await this.adapter.getObjectAsync(this.adapter.namespace + '.' + this.senderID);
if (dev !== null) {
//set RSSI
await this.adapter.setStateAsync(this.telegram.senderID + '.rssi', {val: - this.rssi, ack: true});
//create object repeated for older adapter installation
await this.adapter.setObjectNotExistsAsync(this.telegram.senderID + '.repeated', {
type: 'state',
common: {
name: 'Count of repeated telegrams',
role: 'indicator',
type: 'number',
read: true,
write: false
},
native: {}
});
await this.adapter.setStateAsync(this.telegram.senderID + '.repeated', {val: parseInt(this.repeaterCount), ack: true});
await processMessage(dev, this);
}
}
async setState(deviceId, shortcut, value){
await this.adapter.setStateAsync(this.adapter.namespace + '.' + deviceId + '.' + shortcut, {val: value, ack: true});
}
async extendObject(deviceId, shortcut, obj){
await this.adapter.extendObjectAsync(this.adapter.namespace + '.' + deviceId + '.' + shortcut, obj);
}
/*logInfo(variable){
const info = {};
info.type = typeof variable;
info.length = variable.length;
if(typeof variable !== 'string' || typeof variable !== 'number'){
info.value = JSON.stringify(variable);
}
info.value = variable;
this.adapter.log.info(JSON.stringify(info));
}*/
}
class handleType2{
/**
* RESPONSE
* @param {Object} that
* @param {Object} ESP3Packet
*/
constructor(that, ESP3Packet) {
this.adapter = that;
this.info = that.log.info;
this.telegram = new ResponseTelegram(ESP3Packet);
this.senderID = this.telegram.senderID;
// this.tType = this.telegram.type;
// this.rssi = ESP3Packet.optionalData['5'];
//bind class functions to context of constructor
//this.main.bind(this);
//this.main();
}
get main(){
const returnCode = this.telegram.returnCode;
const answer = {};
switch (parseInt(returnCode.toString('hex'), 16)){
case 0x00:
answer.code = 'OK';
break;
case 0x01:
answer.code = 'ERROR';
break;
case 0x02:
answer.code = 'NOT SUPPORTED';
break;
case 0x03:
answer.code = 'WRONG PARAMETER';
break;
case 0x04:
answer.code = 'OPERATION DENIED';
break;
case 0x05:
answer.code = 'DUTY CYCLE LOCK';
break;
case 0x06:
answer.code = 'BUFFER TO SMALL';
break;
case 0x07:
answer.code = 'NO FREE BUFFER';
break;
}
if(this.telegram.dataLength > 1){
answer.data = this.telegram.data.toString('hex');
}
if(this.telegram.optionalLength > 1){
answer.optionalData = this.telegram.optionalData.toString('hex');
}
return answer;
}
}
class handleType4{
/**
* EVENT
* @param {Object} that
* @param {Object} esp3packet
* @param {Object} teachinInfo
*/
constructor(that, esp3packet, teachinInfo){
this.adapter = that;
this.sendData = that.sendData;
this.log = that.log;
this.debug = that.log.debug;
this.info = that.log.info;
// this.esp3packet = esp3packet;
this.telegram = new EventTelegram(esp3packet);
this.code = this.telegram.eventCode;
this.data = this.telegram.eventData;
this.teachinInfo = teachinInfo;
this.main.bind(this);
this.main();
}
async main(){
switch(this.code){
case '01':
//SA_RECLAIM_NOT_SUCCESSFULL
this.debug('Smart ACK reclaim was not successfully');
break;
case '02': {
//SA_CONFIRM_LEARN
const priority = this.data.slice(0, 1).toString('hex');
// const mfrIdMSB = this.data.slice(1, 2).toString('hex');
const mfrIdLSB = Enocean_manufacturer['0x0' + this.data.slice(2, 3).toString('hex')];
const rorg = this.data.slice(3, 4).toString('hex');
const func = this.data.slice(4, 5).toString('hex');
const type = this.data.slice(5, 6).toString('hex');
const rssi = this.data.slice(6, 7).toString('hex');
const candidateId = this.data.slice(7, 11).toString('hex');
const clientId = this.data.slice(11, 15).toString('hex');
const hops = this.data.slice(15, 16).toString('hex');
this.info(`Received Smart ACK learn confirmation: Priority ${priority}, ${mfrIdLSB}, ${rorg}-${func}-${type}, ${rssi} dBm, ${candidateId}, Candidate ID ${clientId}, Client ID ${clientId}, Hop Count ${hops}`);
const data = Buffer.from([0x00, 0x00, 0x80, 0x00]);
setTimeout( async () => {
await this.sendData(this.adapter, data, null, 2);
/*const readLernmode = Buffer.from([0x02]);
await this.sendData(readLernmode, null, 6);*/
await this.sendData(this.adapter, Buffer.from([0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), null, 6);
setTimeout( async () => {
//await this.sendData(Buffer.from([0xd2, 0x00, 0x01, 0x9d, 0x45, 0x44]), null, 1);
}, 21 * 1000);
},100);
new predefinedDeviceTeachIn(this.adapter, this.teachinInfo.name, this.teachinInfo.mfr, clientId);
this.adapter.setState('gateway.teachin', {val: false, ack: true});
break;
}
case '03':{
//SA_LEARN_ACK
const responseTime = ByteArray.from(this.data).getValue(7, 2).toString(16).toUpperCase();
const confirmCode = ByteArray.from(this.data).getValue(9, 1);
let confirm;
switch(confirmCode){
case 0x00:
confirm = 'Learn in';
break;
case 0x11:
confirm = 'Discard Learn IN, EEP not accepted';
break;
case 0x12:
confirm = 'Discard Learn IN, PM has no place for further MB';
break;
case 0x13:
confirm = 'Discard Learn IN, Controller has no place for new sensor';
break;
case 0x14:
confirm = 'Discard Learn IN, RSSI was not good enough';
break;
case 0x20:
confirm = 'Learn OUT';
break;
}
this.info(`Received Smart ACK learn result: Response Time ${responseTime}, ${confirm}`);
break;
}
case '04': {
//CO_READY
const wCause = ByteArray.from(this.data).getValue(7, 1);
const mode = this.telegram.optionalData;
let wakeup;
switch (wCause){
case 0x00:
wakeup = 'Voltage supply drop or indicates that VDD > VON';
break;
case 0x01:
wakeup = 'Reset caused by usage of the reset pin (is set also after downloading the program with the programmer)';
break;
case 0x02:
wakeup = 'Watchdog timer counter reached the timer period';
break;
case 0x03:
wakeup = 'Flywheel timer counter reached the timer period';
break;
case 0x04:
wakeup = 'Parity error';
break;
case 0x05:
wakeup = 'HW Parity error in the Internal or External Memory';
break;
case 0x06:
wakeup = 'A memory request from the CPU core does not correspond to any valid memory location. This error may be caused by a S/W malfunction.';
break;
case 0x07:
wakeup = 'Wake-up pin 0 activated';
break;
case 0x08:
wakeup = 'Wake-up pin 1 activated';
break;
case 0x09:
wakeup = 'Unknown reset source – reset reason could not be detected';
break;
case 0x10:
wakeup = 'UART Wake up';
break;
}
let security = '';
if(mode === 0x00){
security = 'Standard Security';
}else if(mode === 0x01){
security = 'Extended Security';
}
this.info(`Event ready received: Wakeup reason ${wakeup}, ${security}`);
break;
}
case '05': {
//CO_EVENT_SECUREDEVICES
const cause = ByteArray.from(this.data).getValue(7, 1);
const deviceId = ByteArray.from(this.data).getValue(8, 4).toString(16).toUpperCase();
let eCause = '';
switch (cause) {
case 0x00:
eCause = 'Teach-in failed because no more space available in secure link table.';
break;
case 0x01:
eCause = 'Reserved';
break;
case 0x02:
eCause = 'Resynchronization attempt with wrong private key.';
break;
case 0x03:
eCause = 'Configured count of telegrams with wrong CMAC received.';
break;
case 0x04:
eCause = 'Teach-In failed. Telegram corrupted.';
break;
case 0x05:
eCause = 'PSK Teach-In failed. No PSK is set for the device.';
break;
case 0x06:
eCause = 'Teach-In failed. Trying to teach-in without Pre-Shared Key even if the PSK is set for the device.';
break;
case 0x07:
eCause = 'CMAC or RLC not correct';
break;
case 0x08:
eCause = 'Standard Telegram from device in secure link table.';
break;
case 0x09:
eCause = 'Teach-In successful.';
break;
case 0x0A:
eCause = 'Received valid RLC sync via Teach-In';
break;
}
this.info(`Event securedevices received: ${deviceId}, ${eCause}`);
break;
}
case '06': {
//CO_DUTYCYCLE_LIMIT
const cause = ByteArray.from(this.data).getValue(7, 1);
if(cause === 0x00){
this.info('Duty cycle limit not yet reached. It is possible to send telegrams');
}else if(cause === 0x01){
this.adapter.log.warn('Duty cycle limit reached. It is not possible to send telegrams');
}
break;
}
case '07': {
//CO_TRANSMIT_FAILED
const cause = ByteArray.from(this.data).getValue(7, 1);
if(cause === 0x00){
this.adapter.log.warn('CSMA failed, channel not free');
}else if(cause === 0x01){
this.adapter.log.warn('No Acknowledge received, telegram was transmitted, but no ack received.');
}
break;
}
case '08':
//CO _TX_DONE
this.debug('All transmissions finished.');
break;
case '09':
//CO_LRN_MODE_DISABLED
this.info('Teach-in mode disabled.');
break;
}
}
}
class handleType10{
/**
* RADIO_ERP2
* @param {Object} that
* @param {Object} esp3packet
*/
constructor(that, esp3packet){
this.adapter = that;
this.sendData = that.sendData;
this.log = that.log;
this.debug = that.log.debug;
this.info = that.log.info;
this.telegram = new RadioTelegram_ERP2(esp3packet);
this.senderID = this.telegram.senderID;
this.main.bind(this);
this.main();
}
async main() {
if(!this.telegram.senderID) {
return;
}
const dev = await this.adapter.getObjectAsync(this.telegram.senderID);
if (dev !== null) {
//create object repeated for older adapter installation
await this.adapter.setObjectNotExistsAsync(this.telegram.senderID + '.repeated', {
type: 'state',
common: {
name: 'Count of repeated telegrams',
role: 'indicator',
type: 'number',
read: true,
write: false
},
native: {}
});
await this.adapter.setStateAsync(this.telegram.senderID + '.repeated', {val: parseInt(this.telegram.repeaterCount), ack: true});
this.adapter.log.debug('Message for ID ' + this.telegram.senderID + ' has been received. It was repeated ' + this.telegram.repeaterCount + ' times.');
await processMessage(dev, this);
}
}
async setState(deviceId, shortcut, value){
await this.adapter.setStateAsync(this.adapter.namespace + '.' + deviceId + '.' + shortcut, {val: value, ack: true});
}
async extendObject(deviceId, shortcut, obj){
await this.adapter.extendObjectAsync(this.adapter.namespace + '.' + deviceId + '.' + shortcut, obj);
}
/*logInfo(variable){
const info = {};
info.type = typeof variable;
info.length = variable.length;
if(typeof variable !== 'string' || typeof variable !== 'number'){
info.value = JSON.stringify(variable);
}
info.value = variable;
this.adapter.log.info(JSON.stringify(info));
}*/
}
class handleTeachIn{
/**
*
* @param {Object} that
* @param {Object} ESP3Packet
* @param {Object} teachinInfo
*/
constructor(that, ESP3Packet, teachinInfo = null) {
this.adapter = that;
this.sendData = that.sendData;
this.log = that.log;
this.ESP3Packet = ESP3Packet;
this.info = teachinInfo;
this.name = this.info.name;
this.main.bind(this);
this.main();
}
async main() {
if(this.adapter.config.gateway === 'fgw14-usb'){
this.telegram = new RadioTelegram_ERP2(this.ESP3Packet);
} else {
this.telegram = new RadioTelegram(this.ESP3Packet);
}
this.senderID = this.telegram.senderID;
this.tType = this.telegram.type;
if(this.info) this.tType = this.info.teachinMethod;
this.adapter.log.debug(`teachinMethod: ${this.tType} from ID "${this.senderID}"`);
switch(this.tType) {
case 'A5':
case '4BS':
case FourBS:
{
const teachinData = new FourBSTeachIn(this.telegram.userData);
if (teachinData.teachIn === 0) {
const FUNC = await addLeadingZero(teachinData.EEPFunc.toString(16));
const TYPE = await addLeadingZero(teachinData.EEPType.toString(16));
const MANUFACTURER = Enocean_manufacturer['0x0' + await addLeadingZero( teachinData.mfrID.toString(16)) ];
const gateway = await this.adapter.getObjectAsync('gateway');
const baseID = ByteArray.from( gateway.native.BaseID.match(/.{1,2}/g) );
//Teach-In variations (LRNtype): 0 = without EEP and Manufacturer ID, 1 = with EEP and Manufacturer ID
if (teachinData.LRNtype === 1 && teachinData.LRNStatus === 0) {
const type = [0xA5];
const subTelNum = [0x00];
const tempId = this.senderID.toUpperCase().match(/.{1,2}/g);
const receiverID = [];
for(const b in tempId){
// receiverID.push('0x' + tempId[b]);
receiverID.push(parseInt(tempId[b], 16));
}
const optionalData = subTelNum.concat(receiverID, [0xFF, 0x00]);
const data = ByteArray.from();
data.setValue(parseInt(FUNC, 16), 0, 6); //FUNC
data.setValue(parseInt(TYPE, 16), 6, 7); //TYPE
data.setValue(2047, 13, 11); //Manufacturer ID
data.setValue(1, 24, 1); //LRN Type
data.setValue(1, 25, 1); //EEP Result
data.setValue(1, 26, 1); //LRN Result
data.setValue(1, 27, 1); //LRN Status
data.setValue(0, 28, 1); //LRN Bit
const finalData = type.concat(data, baseID, 0x00);
await this.sendData(this.adapter, finalData, optionalData, 0x01);
this.adapter.log.info(`EEP A5-${FUNC}-${TYPE} detected for device with ID ${this.senderID}, manufacturer: ${MANUFACTURER}`);
new predefinedDeviceTeachIn(this.adapter, this.info.name, this.info.mfr, this.senderID);
//await createObjects(this, `A5-${FUNC}-${TYPE}`, MANUFACTURER);
this.adapter.setState('gateway.teachin', {val: false, ack: true});
} else if (teachinData.LRNtype === 0) {
const lrnStatus = ByteArray.from(this.telegram.userData).getValue(27, 1);
const lrnResult = ByteArray.from(this.telegram.userData).getValue(26, 1);
const eepResult = ByteArray.from(this.telegram.userData).getValue(25, 1);
this.adapter.log.debug(`LRN Status: ${lrnStatus}, LRN Result: ${lrnResult}, EEP Result: ${eepResult} The ID is "${this.senderID}"`);
this.adapter.log.info(`Teach-In: 4BS (A5) Telegram without EEP and manufacturer ID detected, you have to add this device manually. The ID is "${this.senderID}"`);
this.adapter.setState('gateway.teachin', {val: false, ack: true});
} else if (teachinData.LRNStatus === 0) {
const type = [0xA5];
const subTelNum = [0x00];
const tempId = this.senderID.toUpperCase().match(/.{1,2}/g);
const receiverID = [];
for(const b in tempId){
//receiverID.push('0x' + tempId[b]);
receiverID.push(parseInt(tempId[b], 16));
}
const optionalData = subTelNum.concat(receiverID, [0xFF, 0x00]);
const data = ByteArray.from([0x00, 0x00, 0x00, 0x00]);
data.setValue(1, 24, 1); //LRN Type
data.setValue(1, 25, 1); //EEP Result
data.setValue(1, 26, 1); //LRN Result
data.setValue(1, 27, 1); //LRN Status
data.setValue(0, 28, 1); //LRN Bit
const finalData = type.concat(data, baseID, 0x00);
await this.sendData(this.adapter , finalData, optionalData, 0x01);
this.adapter.setState('gateway.teachin', {val: false, ack: true});
}
}
break;
}
case 'F6':
case 'RPS':
case RPS: {
new predefinedDeviceTeachIn(this.adapter, this.info.name, this.info.mfr, this.senderID);
this.adapter.setState('gateway.teachin', {val: false, ack: true});
break;
}
case 'D4':
case 'UTE':
case UTE: {
//this.adapter.log.info(`Teach-In: UTE (D4) Telegram detected, you have to add this device manually. The ID is "${this.senderID}"`);
const teachinData = new UTETeachIn(this.telegram.userData);
const mfr8LSB = await addLeadingZero( teachinData.IDLSB );
const mfr3MSB = await addLeadingZero( teachinData.IDMSB );
const TYPE = await addLeadingZero( teachinData.EEPType );
const FUNC = await addLeadingZero( teachinData.EEPFunc );
const RORG = await addLeadingZero( teachinData.EEPRorg );
const channels = await addLeadingZero( teachinData.channels );
const gateway = await this.adapter.getObjectAsync('gateway');
const baseID = ByteArray.from( gateway.native.BaseID.match(/.{1,2}/g) );
const obj = await this.adapter.getObjectAsync(this.senderID);
if (obj && (teachinData.request === 2 || teachinData.request === 1)) { //Teach-out
const type = [0xD4];
const subTelNum = [0x01];
const tempId = this.senderID.toUpperCase().match(/.{1,2}/g); //device address who will receive the response
const receiverID = []; //tempId has to be split into array for usage
for (const b in tempId) {
receiverID.push('0x' + tempId[b]);
}
// @ts-ignore
const optionalData = subTelNum.concat(receiverID, [0xFF, 0x00]); //building optional data array
const data = ByteArray.from([0x00, channels, mfr8LSB, 0x00, TYPE, FUNC, RORG ]); //initialize data array//initialize data array
data.setValue(teachinData.communication, 0, 1); //Communication type Uni-/Bi-directional (0/1)
data.setValue(2, 2, 2); //Request type
data.setValue(1, 4, 4); //Command identifier
data.setValue(parseInt(mfr3MSB), 29, 3); //Manufacturer-ID (3 MSB)
const finalData = type.concat(data, baseID, 0x00);
await this.sendData(this.adapter, finalData, optionalData, 0x01); //0x01 = Packet Type ERP1
await this.sendData(this.adapter, finalData, optionalData, 0x01);
await deleteDevice(this, this.senderID);
this.adapter.setState('gateway.teachin', {val: false, ack: true});
} else if ( (teachinData.request === 2 || teachinData.request === 0) && teachinData.response === 0 && (teachinData.communication === 1 || teachinData.communication === 0) ) { //Bidirectional Teach-in/-out request with response
const type = [0xD4];
const subTelNum = [0x01];
const tempId = this.senderID.toUpperCase().match(/.{1,2}/g); //device address who will receive the response
const receiverID = []; //tempId has to be split into array for usage
for (const b in tempId) {
// receiverID.push('0x' + tempId[b]);
receiverID.push(parseInt(tempId[b], 16));
}
const optionalData = subTelNum.concat(receiverID, [0xFF, 0x00]); //building optional data array
const data = ByteArray.from([0x00, channels, mfr8LSB, 0x00, TYPE, FUNC, RORG ]); //initialize data array
data.setValue(teachinData.communication, 0, 1); //Communication type Uni-/Bi-directional (0/1)
data.setValue(1, 2, 2); //Request type
data.setValue(1, 4, 4); //Command identifier
data.setValue(parseInt(mfr3MSB), 29, 3); //Manufacturer-ID (3 MSB)
const finalData = type.concat(data, baseID, [0x00]);
await this.sendData(this.adapter, finalData, optionalData, 0x01); //0x01 = Packet Type ERP1
await this.sendData(this.adapter, finalData, optionalData, 0x01);
await createObjects(this, `${RORG}-${FUNC}-${TYPE}`, Enocean_manufacturer[`0x0${mfr8LSB}`]);
this.adapter.setState('gateway.teachin', {val: false, ack: true});
} else if ( (teachinData.request === 2 || teachinData.request === 0) && teachinData.response === 1 && (teachinData.communication === 1 || teachinData.communication === 0) ) { //Bidirectional Teach-in/-out request without response
await createObjects(this, `${RORG}-${FUNC}-${TYPE}`, Enocean_manufacturer[`0x0${mfr8LSB}`]);
this.adapter.setState('gateway.teachin', {val: false, ack: true});
}
//this.adapter.log.info(`Universal Teach-in: Communication: ${teachinData.communication}, Teach-In-Response: ${teachinData.response}, Teach-in-Request: ${teachinData.request}, Command: ${teachinData.cmd}, Channels: ${teachinData.channels}, MFR8LSB: ${mfr8LSB.toString(16)}, MFR3MSB: ${mfr3MSB.toString(16)}, RORG: ${RORG.toString(16)}, FUNC: ${FUNC.toString(16)}, TYPE: ${TYPE.toString(16)}`);
break;
}
case 'D5':
case OneBS: {
const teachinData1BS = new OneBSTeachIn(this.telegram.userData);
if (teachinData1BS.teachIn === 0) {
this.adapter.log.info(`Teach-In: 1BS (D5) Telegram detected, you have to add this device manually. The ID is "${this.senderID}"`);
this.adapter.setState('gateway.teachin', {val: false, ack: true});
}
break;
}
case 'D2':
case VLD:
this.adapter.log.info(`Teach-In: VLD (D2) Telegram detected, you have to add this device manually. The ID is "${this.senderID}"`);
this.adapter.setState('gateway.teachin', {val: false, ack: true});
break;
case 'D1':
case 'MSC':
case MSC: {
const teachinData = new MSCTelegram(this.telegram.userData);
const mfr = teachinData.mfrID;
const gateway = await this.adapter.getObjectAsync('gateway');
const baseID = gateway.native.BaseID;
const offset = gateway.native.BaseID_offset;
if (mfr === 'D') { //check if manufacturer is Eltako
await addEltakoDevice(this, baseID, offset);
} else {
this.adapter.log.info(`Teach-In: MSC (D1) Telegram detected, you have to add this device manually. The ID is "${this.senderID}" and the manufacturer is ${Enocean_manufacturer['0x0' + mfr]}`);
this.adapter.setState('gateway.teachin', {val: false, ack: true});
}
break;
}
case 'D0':{
break;
}
}
}
}
class manualTeachIn {
/**
*
* @param {object} that
* @param {string} eep
* @param {string} mfr
* @param {string} id
* @param {string} name
* @param {string} baseIDoffset
* @param {string} broadcast
*/
constructor(that, eep, mfr, id, name, baseIDoffset, broadcast){
this.adapter = that;
this.eep = eep;
this.mfr = mfr;
this.senderID = id;
this.name = name;
this.IDoffset = baseIDoffset;
this.broadcast = broadcast;
this.main.bind(this);
this.main();
}
async main(){
await createObjects(this, this.eep, this.mfr);
}
}
class predefinedDeviceTeachIn {
/**
*
* @param {object} that
* @param {string} device
* @param {string} mfr
* @param {string} id
*/
constructor(that, device, mfr, id){
this.adapter = that;
this.device = device;
this.mfr = mfr;
this.senderID = id;
this.main.bind(this);
this.main();
}
async main(){
const device = devices[this.mfr][this.device];
this.name = this.device;
this.IDoffset = device.id_offset;
this.broadcast = device.broadcast;
for (const i in device.EEP){
await createObjects(this, device.EEP[i], this.mfr);
}
if(device.EEP.length > 0){
await this.adapter.extendObjectAsync(this.senderID.toLowerCase(), {
'native': {
eep: device.EEP
}
});
}
}
}
/**
*
* @param {object} _this
* @param {string} eep
* @param {string} mfr
* @returns {Promise<void>}
*/
async function createObjects(_this, eep, mfr){
eep = eep.toUpperCase();
_this.adapter.log.info(`Create objects for ${eep} from ${mfr} with id: ${_this.senderID}`);
if(mfr === null){
mfr = 'EnOcean GmbH';
}
const alias = eep.replace(/-/g, '');
//Check if profile exists is not abort createObjects
if(alias === undefined){
return;
}
if (!EEPList[alias]) {
_this.adapter.log.info(`EEP ${eep} unknown, send this information to developer.`);
return;
}
const obj = await _this.adapter.getObjectAsync(_this.senderID);
const id = _this.senderID.toLowerCase();
if (!obj) {
const deviceObj = {
type: 'device',
common: {
name: _this.name ? _this.name : EEPList[alias].type_title
},
native: {
id: id,
eep: [
eep
],
manufacturer: mfr,
name: _this.name ? _this.name : null
}
};
if (_this.IDoffset) {
const gateway = await _this.adapter.getObjectAsync('gateway');
const senderIDs = gateway.native.senderIDs;
let exists = true;
let nextEmptyId = null;
//go through all IDs in index
for(const s in senderIDs){
//check if the Device ID is already in the index, stop for loop if yes
if(senderIDs[s] === id){
deviceObj.native.Sender_ID = s;
exists = true;
break;
} else if(senderIDs[s] === '' && nextEmptyId === null){
nextEmptyId = s;
} else {
exists = false;
}
}
if(exists === false) {
deviceObj.native.Sender_ID = nextEmptyId;
// @ts-ignore
senderIDs[nextEmptyId] = id;
}
//leave offset for compability reasons with versions lower 0.3.x
let offset;
if(gateway.native.BaseID_offset >= 0){
offset = gateway.native.BaseID_offset + 1;
await _this.adapter.extendObjectAsync('gateway', {
'native': {
'BaseID_offset': offset,
'senderIDs': senderIDs
}
});
}else{
await _this.adapter.extendObjectAsync('gateway', {
'native': {
'BaseID_offset': 0,
'senderIDs': senderIDs
}
});
}
deviceObj.native.baseIDoffset = offset;
}
await _this.adapter.setObjectNotExistsAsync(id, deviceObj);
if (_this.broadcast) {
await _this.adapter.extendObjectAsync(id.toLowerCase(), {
'native': {
'broadcast': true
}
});
}
await _this.adapter.setObjectNotExistsAsync(id + '.rssi', {
type: 'state',
common: {
name: 'Signal Strength',
role: 'value.rssi',
type: 'number',
read: true,
write: false,
unit: 'dBm'
},
native: {}
});
await _this.adapter.setObjectNotExistsAsync(id + '.repeated', {
type: 'state',
common: {
name: 'Count of repeated telegrams',
role: 'indicator',
type: 'number',
read: true,
write: false
},
native: {}
});
} else {
const newEEP = obj.native.eep;
let exists = false;
for (const e in newEEP) {
if (newEEP[e] === eep) {
exists = true;
}
}
if (!exists) {
newEEP.push(eep);
await _this.adapter.extendObjectAsync(id.toLowerCase(), {
native: {
eep: newEEP
}
});
}
}
let preDefinedObjects = [];
if(EEPList[alias].objects.preDefined) { preDefinedObjects = EEPList[alias].objects.preDefined; }
for(const p in preDefinedObjects) {
await _this.adapter.extendObjectAsync(`${id}.${preDefinedObjects[p]}`, objDef[preDefinedObjects[p]]);
}
for(const o in EEPList[alias].objects) {
if(o !== 'preDefined'){
await _this.adapter.extendObjectAsync(`${id}.${o}`, EEPList[alias].objects[o]);
}
}
}
/**
* Invert bit string (normal used for msb)
* @param {number} bitString
* @returns {Promise<string>}
*/
async function invertBitString(bitString){
return bitString.toString(2).split('').reverse().join('');
}
/**
*
* @param {string} data
*/
async function addLeadingZero(data) {
if (data.length === 1) {
return data.padStart(2, '0');
} else {
return data;
}
}
/**
* get Value from data telegram
* @param {any} telegram
* @param {object} data - datafield description from EEP file
* @returns {Promise<{val: (Promise<{val: *, shortcut: *}>|number|string), shortcut}>}
*/
async function getValue(telegram, data){
const shortcut = data.shortcut ? data.shortcut : '';
const bitoffs = parseInt(data.bitoffs);
const bitsize = parseInt(data.bitsize);
const value = ByteArray.from(telegram).getValue(bitoffs, bitsize);
return {shortcut: shortcut, val: value};
}
async function convertValue(datafield, value, that) {
/**
* @type {boolean|number|string|null}
*/
let test = false;
let condition = false;
let unit = null;
let secondArg; //if secondArgument is given this will be filled with this value that comes from other datafield
if(datafield.bitType && datafield.bitType === 'MSB'){
value = await invertBitString(value);
}
if (datafield.secondArgument && !datafield.secondArgument.bitType) {
secondArg = await getValue(that.telegram.userData, datafield.secondArgument);
test = jsonLogic.apply(datafield.condition, {'value': value, 'value2': secondArg.val});
if (test === false) {
test = null;
} else {
condition = true;
}
}else if(datafield.secondArgument && datafield.secondArgument.bitType === 'MSB'){
secondArg = await getValue(that.telegram.userData, datafield.secondArgument);
// @ts-ignore
test = await invertBitString(secondArg.val);
}else if (datafield.condition) {
test = jsonLogic.apply(datafield.condition, {'value': value});
}
if(test !== null && datafield.value){
test = jsonLogic.apply(datafield.value, {'value': value});
}
if(datafield.secondArgument && test === null && datafield.value && condition === true){
secondArg = await getValue(that.telegram.userData, datafield.secondArgument);
test = jsonLogic.apply(datafield.value, {'value': value, 'value2': secondArg.val});
}
if(typeof test === 'number' && datafield.decimals){
const num = Number(test);
test = parseFloat(num.toFixed(datafield.decimals));
}
if(datafield.unit && secondArg !== undefined){
unit = jsonLogic.apply(datafield.unit, {'value2': secondArg.val});
}
return {newVal: test, unit: unit};
}
async function processMessage(dev, that) {
const eep = dev.native.eep;
const rorg = that.telegram.type.toString(16).toUpperCase();
for (const e in eep) {
const eep1 = eep[e].replace(/-/g, '');
const profile = EEPList[eep1];
const rorgIn = profile.rorg_number.replace('0x', '');
if (rorg === rorgIn) {
for (const c in profile.case) {
//Check if there are conditions to choose the right data handling
//conditions are optional
let conditionResult = null;
if (profile.case[c].condition !== undefined) {
for (const s in profile.case[c].condition) {
const keys = Object.keys(profile.case[c].condition);
if (keys[0] === 'statusfield') { //statusfield has to be defined as the first condition
const condition = profile.case[c].condition[s];
if (condition.length !== undefined) {
for (const con in profile.case[c].condition[s]) {
const check = profile.case[c].condition[s][con];
const bitoffs = parseInt(check.bitoffs);
const bitsize = parseInt(check.bitsize);
const value = ByteArray.from(that.telegram.status).getValue(bitoffs, bitsize);
if (value === parseInt(check.value) && conditionResult !== false) {
conditionResult = true;
} else {
conditionResult = false;
}
}
}
} else {
const condition = profile.case[c].condition[s];
if (condition.length !== undefined) {
for (const con in profile.case[c].condition[s]) {
const check = profile.case[c].condition[s][con];
const bitoffs = parseInt(check.bitoffs);
const bitsize = parseInt(check.bitsize);
const value = ByteArray.from(that.telegram.userData).getValue(bitoffs, bitsize);
const testResult = jsonLogic.apply(check.value, {'value': value});
if (testResult === true || value === parseInt(check.value) && (conditionResult !== false || conditionResult === null)) {
conditionResult = true;
} else {
conditionResult = false;
}
}
} else {
const check = profile.case[c].condition[s];
const bitoffs = parseInt(check.bitoffs);
const bitsize = parseInt(check.bitsize);
const value = ByteArray.from(that.telegram.userData).getValue(bitoffs, bitsize);
const testResult = jsonLogic.apply(check.value, {'value': value});
if (testResult === true || value === parseInt(check.value) && (conditionResult !== false || conditionResult === null)) {
conditionResult = true;
} else {
conditionResult = false;
}
}
}
}
}
//look for data and decode them
if (conditionResult === true || conditionResult === null) {
if (profile.case[c].datafield !== undefined) {
for (const x in profile.case[c].datafield) {
const datafield = profile.case[c].datafield[x];
const {shortcut, val} = await getValue(that.telegram.userData, datafield);
const {newVal, unit} = await convertValue(datafield, val, that);
if (!shortcut) {
break;
}
if (newVal !== null) {
await that.setState(that.telegram.senderID, shortcut, newVal);
}
if (unit !== null) {
await that.extendObject(that.telegram.senderID, shortcut, {common: {unit: unit}});
}
}
} else {
for (const z in profile.case[c]) {
const datafield = profile.case[c][z];
const {shortcut, val} = await getValue(that.telegram.userData, datafield);
const {newVal, unit} = await convertValue(datafield, val, that);
if (newVal !== null) {
that.setState(that.telegram.senderID, shortcut, newVal);
}
if (unit !== null) {
that.extendObject(that.telegram.senderID, shortcut, {common: {unit: unit}});
}
}
}
}
//Check if device waits for a direct answer
if(profile.case[c].auto_answer === true) {
const parameter = [];
const data = ByteArray.from();
for (const d in profile.case[c].datafield) {
const datafield = profile.case[c].datafield[d];
if (datafield.data === 'fixed parameter') {
const bitoffs = datafield.bitoffs;
const bitsize = datafield.bitsize;
data.setValue(datafield.value, bitoffs, bitsize);
} else {
parameter.push(datafield.shortcut);
}
}
//get data from objects
for (const s in parameter) {
const state = await that.adapter.getStateAsync(`${that.adapter.namespace}.${that.telegram.senderID}.${parameter[s]}`);
await that.setState(`${that.adapter.namespace}.${that.telegram.senderID}.${parameter[s]}`, {ack: true});
const short = parameter[s];
const datafield = profile.case[c].datafield;
for (const d in datafield) {
if (state !== null && datafield[d].shortcut === short && datafield[d].bitoffs !== null && datafield[d].bitsize !== null && (!datafield[d].condition && !datafield[d].condition[0].value === state.val)) {
const bitoffs = datafield[d].bitoffs;
const bitsize = datafield[d].bitsize;
const value = state.val;
//Check if there is a converion needed
if (datafield[d].value_out) {
const convertedValue = jsonLogic.apply(datafield[d].value_out, {'value': value});
data.setValue(parseInt(convertedValue), bitoffs, bitsize);
} else if (value) {
data.setValue(value, bitoffs, bitsize);
}
break;
} else if (datafield[d].shortcut === short && datafield[d].bitoffs !== null && datafield[d].bitsize !== null && datafield[d].value !== null && datafield[d].value !== undefined) {
const bitoffs = datafield[d].bitoffs;
const bitsize = datafield[d].bitsize;
const value = datafield[d].value;
data.setValue(value, bitoffs, bitsize);
}
}
}
const subTelNum = [0x00];
if(dev.native.broadcast){
that.telegram.senderID = 'ffffffff';
}
const tempId = that.telegram.senderID.toUpperCase().match(/.{1,2}/g);
const receiverID = [];
for(const b in tempId) {
// receiverID.push('0x' + tempId[b]);
receiverID.push(parseInt(tempId[b], 16));
}
const gateway = await that.adapter.getObjectAsync('gateway');
let baseID = gateway.native.BaseID;
if (dev.native.Sender_ID) {
baseID = dev.native.Sender_ID;
}
baseID = ByteArray.from(baseID.match(/.{1,2}/g));
const optionalData = subTelNum.concat(receiverID, [0xFF, 0x00]);
let type, finalData;
switch (rorg) {
case 'D2': {
type = [0xD2];
finalData = type.concat(data, baseID, [0x00]);
break;
}
case 'A5': {
type = [0xA5];
if (data.length > 4 || data.length < 4) {
that.adapter.log.warn(`The data length for a 4BS telegram is incorrect. The length is ${data.length}`);
}
finalData = type.concat(data, baseID, [0x00]);
break;
}
case 'F6': {
type = [0xF6];
if (data.length > 1 || data.length < 1) {
that.adapter.log.warn(`The data length for a RPS telegram is incorrect. The length is ${data.length}`);
}
finalData = type.concat(data, baseID, [0x30]);
break;
}
case 'D5': {
type = [0xD5];
if (data.length > 1 || data.length < 1) {
that.adapter.log.warn(`The data length for a 1BS telegram is incorrect. The length is ${data.length}`);
}
finalData = type.concat(data, baseID, [0x00]);
break;
}
}
that.adapter.queue.push({'data': finalData, 'optionaldata': optionalData, 'packettype': 0x01});
}
}
}
}
}
/**
*
* @param {object} _this
* @param {string} deviceId
* @returns {Promise<void>}
*/
async function deleteDevice(_this, deviceId) {
await _this.adapter.getObjectListAsync({startkey: _this.adapter.namespace + '.' + deviceId, endkey: _this.adapter.namespace + '.' + deviceId + '.\u9999'})
.then(async result => {
for (const r in result.rows) {
await _this.adapter.delObjectAsync(result.rows[r].id)
.then(result => {
_this.adapter.log.debug(result);
}, reject => {
_this.adapter.log.error(reject);
});
}
}, reject => {
_this.adapter.log.error(reject);
});
}
/**
*
* @param {string} baseID
* @param {number} summand
* @returns {Promise<string>}
*/
async function additionID(baseID, summand){
const patt = new RegExp(/^0x/);
if(!patt.test(baseID)) {
baseID = '0x' + baseID;
}
const idDec = parseInt(baseID) + summand;
return idDec.toString(16);
}
async function addEltakoDevice(_this, baseID, offset) {
const patt = new RegExp('00d0fe');
const res = patt.test(_this.telegram.userData);
if (res) {
return;
}
const devTelegram = _this.telegram.userData.replace('00d0ff', '').toUpperCase();
const type = [0xA5];
const subTelNum = [0x01];
const tempId = _this.senderID.toUpperCase().match(/.{1,2}/g); //device address who will receive the response
const receiverID = []; //tempId has to be split into array for usage
for (const b in tempId) {
// receiverID.push('0x' + tempId[b]);
receiverID.push(parseInt(tempId[b], 16));
}
const optionalData = subTelNum.concat(receiverID, [0xFF, 0x00]); //building optional data array
const offs = (offset !== undefined) ? parseInt(offset) + 1 : 0;
const newIDdecimal = await additionID(baseID, offs);
const newID = ByteArray.from( newIDdecimal.match(/.{1,2}/g) );
_this.IDoffset = true;
if (!eltakoDevices[devTelegram]) {
_this.adapter.log.info(`Could not identify teachin telegram, ${devTelegram}, from Eltako device.`);
return;
}
switch(eltakoDevices[devTelegram].name) {
case 'fd62np-230v':
case 'fd62npn-230v': {
_this.adapter.setState('gateway.teachin', {val: false, ack: true});
_this.adapter.log.info('Eltako FD62NP(N)-230V detected');
const data = ByteArray.from([0xE0, 0x40, 0x0D, 0x80]); //initialize data array
const finalData = type.concat(data, newID, [0x00]);
setTimeout( async () => {
await _this.sendData(_this.adapter, finalData, optionalData, 0x01); //0x01 = Packet Type ERP1
await _this.sendData(_this.adapter, finalData, optionalData, 0x01); //0x01 = Packet Type ERP1
}, 5 * 1000);
await createObjects(_this, `TF-13-07`, Enocean_manufacturer[`0x00D`]);
await createObjects(_this, `TF-13-06`, Enocean_manufacturer[`0x00D`]);
await _this.adapter.extendObjectAsync(_this.senderID.toLowerCase(), {
'native': {
'eep': ['TF-13-07',
'TF-13-06']
}
});
break;
}
case 'fhk61-230v': {
break;
}
case 'fkld61': {
_this.adapter.setState('gateway.teachin', {val: false, ack: true});
_this.adapter.log.info('Eltako FKLD61 detected');
const data = ByteArray.from([0xE0, 0x40, 0x0D, 0x80]); //initialize data array
const finalData = type.concat(data, newID, [0x00]);
setTimeout( async () => {
await _this.sendData(_this.adapter, finalData, optionalData, 0x01); //0x01 = Packet Type ERP1
await _this.sendData(_this.adapter, finalData, optionalData, 0x01); //0x01 = Packet Type ERP1
}, 5 * 1000);
await createObjects(_this, `TF-13-07`, Enocean_manufacturer[`0x00D`]);
await createObjects(_this, `TF-13-06`, Enocean_manufacturer[`0x00D`]);
await _this.adapter.extendObjectAsync(_this.senderID.toLowerCase(), {
'native': {
'eep': ['TF-13-07', 'TF-13-06']
}
});
break;
}
case 'flc61np': {
break;
}
case 'fld61': {
_this.adapter.setState('gateway.teachin', {val: false, ack: true});
_this.adapter.log.info('Eltako FLD61 detected');
const data = ByteArray.from([0xE0, 0x40, 0x0D, 0x80]); //initialize data array
const finalData = type.concat(data, newID, [0x00]);
setTimeout( async () => {
await _this.sendData(_this.adapter, finalData, optionalData, 0x01); //0x01 = Packet Type ERP1
await _this.sendData(_this.adapter, finalData, optionalData, 0x01); //0x01 = Packet Type ERP1
}, 5 * 1000);
await createObjects(_this, `TF-13-07`, Enocean_manufacturer[`0x00D`]);
await createObjects(_this, `TF-13-06`, Enocean_manufacturer[`0x00D`]);
await _this.adapter.extendObjectAsync(_this.senderID.toLowerCase(), {
'native': {
'eep': ['TF-13-07', 'TF-13-06']
}
});
break;
}
case 'fl62np-230v': {
_this.adapter.setState('gateway.teachin', {val: false, ack: true});
_this.adapter.log.info('Eltako FL62 detected');
const data = ByteArray.from([0xE0, 0x40, 0x0D, 0x80]); //initialize data array
const finalData = type.concat(data, newID, [0x00]);
setTimeout( async () => {
await _this.sendData(_this.adapter, finalData, optionalData, 0x01); //0x01 = Packet Type ERP1
await _this.sendData(_this.adapter, finalData, optionalData, 0x01); //0x01 = Packet Type ERP1
}, 5 * 1000);
await createObjects(_this, `TF-13-11`, Enocean_manufacturer[`0x00D`]);
await createObjects(_this, `TF-14-02`, Enocean_manufacturer[`0x00D`]);
await _this.adapter.extendObjectAsync(_this.senderID.toLowerCase(), {
'native': {
'eep': ['TF-13-11',
'TF-14-02']
}
});
break;
}
case 'fms61np-230v': {
break;
}
case 'fmz61-230v': {
break;
}
case 'fud61np-230v':
case 'fud61npn-230v': {
_this.adapter.setState('gateway.teachin', {val: false, ack: true});
_this.adapter.log.info('Eltako FUD61NPN-230V detected');
const data = ByteArray.from([0xE0, 0x40, 0x0D, 0x80]); //initialize data array
const finalData = type.concat(data, newID, [0x00]);
setTimeout( async () => {
await _this.sendData(_this.adapter, finalData, optionalData, 0x01); //0x01 = Packet Type ERP1
await _this.sendData(_this.adapter, finalData, optionalData, 0x01); //0x01 = Packet Type ERP1
}, 5 * 1000);
await createObjects(_this, `TF-13-07`, Enocean_manufacturer[`0x00D`]);
await createObjects(_this, `TF-13-06`, Enocean_manufacturer[`0x00D`]);
await _this.adapter.extendObjectAsync(_this.senderID.toLowerCase(), {
'native': {
'eep': ['TF-13-07', 'TF-13-06']
}
});
break;
}
case 'fud62npn-ble': {
break;
}
case 'frm60': {
break;
}
case 'fsb61np-230v': {
_this.adapter.setState('gateway.teachin', {val: false, ack: true});
_this.adapter.log.info('Eltako FSB61NP-230V detected');
const data = ByteArray.from([0xFF, 0xF8, 0x0D, 0x80]); //initialize data array
const finalData = type.concat(data, newID, [0x00]);
setTimeout( async () => {
await _this.sendData(_this.adapter, finalData, optionalData, 0x01); //0x01 = Packet Type ERP1
await _this.sendData(_this.adapter, finalData, optionalData, 0x01); //0x01 = Packet Type ERP1
}, 5 * 1000);
await createObjects(_this, `TF-13-03`, Enocean_manufacturer[`0x00D`]);
await createObjects(_this, `TF-13-04`, Enocean_manufacturer[`0x00D`]);
await _this.adapter.extendObjectAsync(_this.senderID.toLowerCase(), {
'native': {
'eep': ['TF-13-03', 'TF-13-04']
}
});
break;
}
case 'fsb62-ble': {
break;
}
case 'fsb64': {
break;
}
case 'fsb71-230v': {
_this.adapter.setState('gateway.teachin', {val: false, ack: true});
_this.adapter.log.info('Eltako FSB61NP-230V detected');
const data = ByteArray.from([0xFF, 0xF8, 0x0D, 0x80]); //initialize data array
const finalData = type.concat(data, newID, [0x00]);
setTimeout( async () => {
await _this.sendData(_this.adapter, finalData, optionalData, 0x01); //0x01 = Packet Type ERP1
await _this.sendData(_this.adapter, finalData, optionalData, 0x01); //0x01 = Packet Type ERP1
}, 5 * 1000);
await createObjects(_this, `TF-13-03`, Enocean_manufacturer[`0x00D`]);
await createObjects(_this, `TF-13-04`, Enocean_manufacturer[`0x00D`]);
await _this.adapter.extendObjectAsync(_this.senderID.toLowerCase(), {
'native': {
'eep': ['TF-13-03', 'TF-13-04']
}
});
break;
}
case 'fsb71-2x-230v': {
break;
}
case 'fsb71-24vdc': {
break;
}
case 'fsg71/1-10v': {
break;
}
case 'fsha': {
break;
}
case 'fsr61-230v': {
_this.adapter.setState('gateway.teachin', {val: false, ack: true});
_this.adapter.log.info('Eltako FSR61 detected');
const data = ByteArray.from([0xE0, 0x40, 0x0D, 0x80]); //initialize data array
const finalData = type.concat(data, newID, [0x00]);
setTimeout( async () => {
await _this.sendData(_this.adapter, finalData, optionalData, 0x01); //0x01 = Packet Type ERP1
await _this.sendData(_this.adapter, finalData, optionalData, 0x01); //0x01 = Packet Type ERP1
}, 5 * 1000);
await createObjects(_this, `TF-01-02`, Enocean_manufacturer[`0x00D`]);
await createObjects(_this, `TF-14-02`, Enocean_manufacturer[`0x00D`]);
await _this.adapter.extendObjectAsync(_this.senderID.toLowerCase(), {
'native': {
'eep': ['TF-01-02', 'TF-14-02']
}
});
break;
}
case 'fsr62-ble': {
break;
}
case 'fsr62np2-ble': {
break;
}
case 'fsr64': {
break;
}
case 'fsr71np-2x-230v': {
break;
}
case 'fsr71np-4x-230v': {
break;
}
case 'fsr71ssr-2x-230v': {
break;
}
case 'ftkb-hg': {
_this.adapter.setState('gateway.teachin', {val: false, ack: true});
_this.adapter.log.info('Eltako FTKB-hg detected');
const data = ByteArray.from([0x50, 0x50, 0x16, 0x80]); //initialize data array
const finalData = type.concat(data, newID, [0x00]);
setTimeout( async () => {
await _this.sendData(_this.adapter, finalData, optionalData, 0x01); //0x01 = Packet Type ERP1
await _this.sendData(_this.adapter, finalData, optionalData, 0x01); //0x01 = Packet Type ERP1
}, 5 * 1000);
await createObjects(_this, `A5-14-0A`, Enocean_manufacturer[`0x00D`]);
await _this.adapter.extendObjectAsync(_this.senderID.toLowerCase(), {
'native': {
'eep': ['A5-14-0A']
}
});
break;
}
case 'ftn61np-230v': {
break;
}
case 'tf-tax5d': {
_this.adapter.setState('gateway.teachin', {val: false, ack: true});
_this.adapter.log.info('Eltako TF-TAx5D detected');
const data = ByteArray.from([0xE0, 0x40, 0x0D, 0x80]); //initialize data array
const finalData = type.concat(data, newID, [0x00]);
setTimeout ( async () => {
await _this.sendData(_this.adapter, finalData, optionalData, 0x01); //0x01 = Packet Type ERP1
await _this.sendData(_this.adapter, finalData, optionalData, 0x01); //0x01 = Packet Type ERP1
}, 5 * 1000);
await createObjects(_this, `TF-01-01`, Enocean_manufacturer[`0x00D`]);
await createObjects(_this, `F6-02-02`, Enocean_manufacturer[`0x00D`]);
await _this.adapter.extendObjectAsync(_this.senderID.toLowerCase(), {
'native': {
'eep': ['TF-01-01', 'F6-02-02']
}
});
break;
}
case 'tf-tax5j': {
_this.adapter.setState('gateway.teachin', {val: false, ack: true});
_this.adapter.log.info('Eltako TF-TAx5J detected');
const data = ByteArray.from([0xFF, 0xF8, 0x0D, 0x80]); //initialize data array
const finalData = type.concat(data, newID, [0x00]);
setTimeout( async () => {
await _