iobroker.oscam
Version:
Integrate Oscam server in iobroker
384 lines (331 loc) • 16.1 kB
JavaScript
'use strict';
const utils = require('@iobroker/adapter-core');
const parseString = require('xml2js').parseString;
class Oscam extends utils.Adapter {
/**
* @param {Partial<utils.AdapterOptions>} [options={}]
*/
constructor(options) {
super({
...options,
name: 'oscam',
});
this.oscamIpAdress = null;
this.oscamPort = null;
this.oscamUser = null;
this.oscamPassword = null;
this.oscamUrl = null;
this.refreshTime = null;
this.digestRequest = null;
this.karten = [];
this.on('ready', this.onReady.bind(this));
this.on('stateChange', this.onStateChange.bind(this));
this.on('unload', this.onUnload.bind(this));
}
async onReady() {
this.setStateAsync('info.connection', false, true);
this.log.debug(`instance config: ${JSON.stringify(this.config)}`);
if (!this.config.serverIp || !this.config.serverPort || !this.config.refreshtime) {
this.log.error (`Check your configuration. Configuation is not complete !`);
return;
}
this.oscamIpAdress = 'http://' + this.config.serverIp ;
this.oscamPort = this.config.serverPort;
this.oscamUser = this.config.userName;
this.oscamPassword = this.config.password;
this.oscamUrl = '/oscamapi.html?part=status';
this.refreshTime = this.config.refreshtime;
// after start let´s first get one time all dp´s
await this.getStatusAndWriteDataPoints();
this.updateInterval = setInterval(async () => {
await this.getStatusAndWriteDataPoints();
}, this.refreshTime * 1000);
// Alle eigenen States abonnieren
this.subscribeStatesAsync('*');
}
onUnload(callback) {
try {
clearInterval(this.updateInterval);
callback();
} catch (e) {
callback();
}
}
/**
* Is called if a subscribed state changes
* @param {string} id
* @param {ioBroker.State | null | undefined} state
*/
onStateChange(id, state) {
// Restart button pressed
const result = id.match(/^oscam.\d+.cards.(\w+).restart$/);
if ( result && state?.val == true )
{
const restartURL= '/status.html?action=restart&label=' + result[1];
this.log.info(`Going to restart Reader : ${result[1]}`);
// call RestartUrl
this.digestRequest = require('request-digest')(this.oscamUser, this.oscamPassword);
this.digestRequest.requestAsync({
host: this.oscamIpAdress,
port: this.oscamPort,
path: restartURL,
method: 'GET',
excludePort: false,
headers: {
'Custom-Header': 'OneValue',
'Other-Custom-Header': 'OtherValue'
}
}).then( () => {
this.log.info (`Reader ${result[1]} restarted !`);
this.log.debug (`Restart sucessfull to ${this.oscamIpAdress} Port ${this.oscamPort} and Url ${restartURL}`);
}).catch(error => {
this.log.error(`${error}`);
if (error.statusCode == 401) {
this.log.error (`Unauthorized access statusCode : ${error.statusCode}`);
this.log.error (`Check your configuration. User and/or Password not correct !`);
}
});
this.setStateAsync(id, {val: false, ack: true} );
}
}
// If you need to accept messages in your adapter, uncomment the following block and the corresponding line in the constructor.
// /**
// * Some message was sent to this instance over message box. Used by email, pushover, text2speech, ...
// * Using this method requires "common.messagebox" property to be set to true in io-package.json
// * @param {ioBroker.Message} obj
// */
// onMessage(obj) {
// if (typeof obj === 'object' && obj.message) {
// if (obj.command === 'send') {
// // e.g. send email or pushover or whatever
// this.log.info('send command');
// // Send response in callback if required
// if (obj.callback) this.sendTo(obj.from, obj.command, 'Message received', obj.callback);
// }
// }
// }
async getStatusAndWriteDataPoints () {
const getAUStatus = (stat) => {
const defaultKey = 'not defined';
const statMap = {
'-1' : 'On',
'1' : 'Auto',
};
return statMap[stat] ?? statMap[defaultKey];
};
this.digestRequest = require('request-digest')(this.oscamUser, this.oscamPassword);
this.digestRequest.requestAsync({
host: this.oscamIpAdress,
port: this.oscamPort,
path: this.oscamUrl,
method: 'GET',
excludePort: false,
headers: {
'Custom-Header': 'OneValue',
'Other-Custom-Header': 'OtherValue'
}
}).then( (response) => {
this.log.info (`Connection established to ${this.oscamIpAdress} Port ${this.oscamPort} and Url ${this.oscamUrl}`);
parseString(response.body, async (err, result) => {
// get Oscam Information
this.log.debug (`Parsing XML Body Response to JSON`);
this.log.debug (`${response.body}`);
await this.setStateAsync('oscaminfo.Version', {val: result.oscam.$.version, ack: true} );
await this.setStateAsync('oscaminfo.Revision', {val: result.oscam.$.revision, ack: true} );
await this.setStateAsync('oscaminfo.Starttime', {val: result.oscam.$.starttime, ack: true} );
await this.setStateAsync('oscaminfo.Uptime', {val: Number(result.oscam.$.uptime), ack: true} );
this.karten=result.oscam.status[0].client;
this.karten.forEach ((karte) => {
// only real cards with type "r" are relevant
if (karte.$.type == 'r') {
// Create channel for every reader
const channel4reader = 'cards.' + karte.$.name;
this.setObjectNotExists(channel4reader, {
type: 'channel',
common: {
name: 'card',
role: 'text'
},
native: {}
});
//Create Status and set Status for every reader
this.setObjectNotExists(channel4reader + '.Status', {
'type': 'state',
'common': {
'role': 'text',
'name': 'Status',
'type': 'string',
'read': true,
'write': false
},
'native': {}
});
this.setStateAsync(channel4reader + '.Status', {val: karte.connection[0]._, ack: true} );
//Create Protocol and set Protocol for every reader
this.setObjectNotExists(channel4reader + '.Protocol', {
'type': 'state',
'common': {
'role': 'text',
'name': 'Protocol',
'type': 'string',
'read': true,
'write': false
},
'native': {}
});
this.setStateAsync(channel4reader + '.Protocol', {val: karte.$.protocol, ack: true} );
//Create AU Flag and set AU Flag for every reader
this.setObjectNotExists(channel4reader + '.AU', {
'type': 'state',
'common': {
'role': 'text',
'name': 'Autoupdate',
'type': 'string',
'read': true,
'write': false
},
'native': {}
});
this.setStateAsync(channel4reader + '.AU', {val: getAUStatus(karte.$.au), ack: true} );
//Create login time and set login time for every reader
this.setObjectNotExists(channel4reader + '.Login time', {
'type': 'state',
'common': {
'role': 'text',
'name': 'Login time',
'type': 'string',
'read': true,
'write': false
},
'native': {}
});
this.setStateAsync(channel4reader + '.Login time', {val: karte.times[0].$.login, ack: true} );
//Create uptime time and set uptime time for every reader
this.setObjectNotExists(channel4reader + '.Uptime', {
'type': 'state',
'common': {
'role': 'text',
'name': 'Uptime in seconds',
'type': 'number',
'read': true,
'write': false
},
'native': {}
});
this.setStateAsync(channel4reader + '.Uptime', {val: Number(karte.times[0].$.online), ack: true} );
//Create Description and set Description for every reader
this.setObjectNotExists(channel4reader + '.Description', {
'type': 'state',
'common': {
'role': 'text',
'name': 'Description',
'type': 'string',
'read': true,
'write': false
},
'native': {}
});
this.setStateAsync(channel4reader + '.Description', {val: karte.$.desc, ack: true} );
//Create caid and set caid for every reader
this.setObjectNotExists(channel4reader + '.CAID', {
'type': 'state',
'common': {
'role': 'text',
'name': 'CAID',
'type': 'string',
'read': true,
'write': false
},
'native': {}
});
this.setStateAsync(channel4reader + '.CAID', {val: karte.request[0].$.caid, ack: true} );
//Create provid and set provid for every reader
this.setObjectNotExists(channel4reader + '.PROVID', {
'type': 'state',
'common': {
'role': 'text',
'name': 'PROVID',
'type': 'string',
'read': true,
'write': false
},
'native': {}
});
this.setStateAsync(channel4reader + '.PROVID', {val: karte.request[0].$.provid, ack: true} );
//Create srvid and set srvid for every reader
this.setObjectNotExists(channel4reader + '.SRVID', {
'type': 'state',
'common': {
'role': 'text',
'name': 'SRVID',
'type': 'string',
'read': true,
'write': false
},
'native': {}
});
this.setStateAsync(channel4reader + '.SRVID', {val: karte.request[0].$.srvid, ack: true} );
//Create ecmtime for every reader
this.setObjectNotExists(channel4reader + '.ecmtime', {
'type': 'state',
'common': {
'role': 'text',
'name': 'ecmtime',
'type': 'string',
'read': true,
'write': false
},
'native': {}
});
this.setStateAsync(channel4reader + '.ecmtime', {val: karte.request[0].$.ecmtime, ack: true} );
//Create ecmtime for every reader
this.setObjectNotExists(channel4reader + '.ecmhistory', {
'type': 'state',
'common': {
'role': 'text',
'name': 'ecmhistory',
'type': 'string',
'read': true,
'write': false
},
'native': {}
});
this.setStateAsync(channel4reader + '.ecmhistory', {val: karte.request[0].$.ecmhistory, ack: true} );
//Create Restart buton for every reader
this.setObjectNotExists(channel4reader + '.restart', {
'type': 'state',
'common': {
'role': 'button',
'name': 'Restart button',
'type': 'boolean',
'read': false,
'write': true,
'desc': 'Restart'
},
'native': {}
});
this.setStateAsync(channel4reader + '.restart', {val: false, ack: true} );
this.setStateAsync('info.connection', true, true);
//this.log.debug (`${JSON.stringify(karte.request[0].$.caid)}`);
} // if
}); // foreach
}); // parsestring
}).catch(error => {
this.log.debug(`${error}`);
if (error.statusCode == 401) {
this.log.error (`Unauthorized access statusCode : ${error.statusCode}`);
this.log.error (`Check your configuration. User and/or Password not correct !`);
}
});
} //getStatusAndWriteDataPoints
} // class Oscam
if (require.main !== module) {
// Export the constructor in compact mode
/**
* @param {Partial<utils.AdapterOptions>} [options={}]
*/
module.exports = (options) => new Oscam(options);
} else {
// otherwise start the instance directly
new Oscam();
}