<commit_before>var adapter = require(__dirname + '/../../lib/adapter.js')({

    name:                   'hm-rpc',

    ready: function () {
        adapter.subscribeStates('*');
        main();
    },
    stateChange: function (id, state) {
        if (state.ack !== true) {
            var tmp = id.split('.');
            adapter.log.debug(adapter.config.type + 'rpc -> setValue ' + JSON.stringify([tmp[2], tmp[3], state.val]));
            if (channelParams[tmp[2]] && metaValues[channelParams[tmp[2]]] && metaValues[channelParams[tmp[2]]][tmp[3]]) {
                if (!(metaValues[channelParams[tmp[2]]][tmp[3]].OPERATIONS & 2)) {
                    adapter.log.warn(adapter.config.type + 'rpc -> setValue ' + JSON.stringify([tmp[2], tmp[3], state.val]) + ' is not writeable');
                }
                var type = metaValues[channelParams[tmp[2]]][tmp[3]].TYPE;
            } else {
                var type = 'UNKNOWN';
            }
            switch (type) {
                case 'BOOL':
                    var val = state.val ? true : false;
                    break;
                case 'FLOAT':
                    var val = {explicitDouble: state.val};
                    break;
                default:
                    var val = state.val;
            }
            rpcClient.methodCall('setValue', [tmp[2], tmp[3], val], function (err, data) {
                if (err) {
                    adapter.log.error(adapter.config.type + 'rpc -> setValue ' + JSON.stringify([tmp[2], tmp[3], state.val]));
                    adapter.log.error(err);
                }
            });
        }
    },
    //  - callback must be called in any case!
    unload: function (callback) {
        try {
            if (adapter.config.init) {
                adapter.config.init = false;
                log.info(adapter.config.type + "rpc -> " + adapter.config.homematicAddress + ':' + adapter.config.homematicPort + ' init ' + JSON.stringify(['http://' + adapter.config.adapterAddress + ':' + adapter.config.homematicPort, '']));
                rpcClient.methodCall('init', ['http://' + adapter.config.adapterAddress + ':' + adapter.config.homematicPort, ''], function (err, data) {
                    adapter.states.setState('system.adapter.' + adapter.namespace + '.connected', {val: false});
                    callback();
                });
            } else {
                callback();
            }
        } catch (e) {
            callback();
        }
    },
    install: function (callback) {
        var design = {
            "_id": "_design/hm-rpc",
            "language": "javascript",
            "views": {
                "listDevices": {
                    "map": "function(doc) {\n  if (doc._id.match(/^hm-rpc\\.[0-9]+\\.\\*?[A-Za-z0-9_-]+(:[0-9]+)?$/)) {\n   emit(doc._id, {ADDRESS:doc.native.ADDRESS,VERSION:doc.native.VERSION,PARENT_TYPE:doc.native.PARENT_TYPE,TYPE:doc.native.TYPE});\n  }\n}"
                },
                "paramsetDescription": {
                    "map": "function(doc) {\n  if (doc._id.match(/^hm-rpc\\.meta/) && doc.meta.type === 'paramsetDescription') {\n   emit(doc._id, doc);\n  }\n}"
                }
            }
        };
        adapter.objects.setObject(design._id, design, function () {
            log.info('object _design/hm-rpc created');
            if (typeof callback === 'function') callback();
        });
    }
});

var rpc;
var rpcClient;
var rpcClientPending;

var rpcServer;
var rpcServerStarted;

var connected;

var metaValues =    {};
var metaRoles =     {};
var channelParams = {};


var xmlrpc = require('xmlrpc');
var iconv = require('iconv-lite');

function main() {
    rpcClient = xmlrpc.createClient({
        host: adapter.config.homematicAddress,
        port: adapter.config.homematicPort,
        path: '/'
    });



    // Load VALUE paramsetDescriptions (needed to create state objects)
    adapter.objects.getObjectView('hm-rpc', 'paramsetDescription', {startkey: 'hm-rpc.meta.VALUES', endkey: 'hm-rpc.meta.VALUES.\u9999'}, function (err, doc) {
        // Todo Handle Errors
        var response = [];
        for (var i = 0; i < doc.rows.length; i++) {
            metaValues[doc.rows[i].id.slice(19)] = doc.rows[i].value.native;
        }
        // Load common.role assignments
        adapter.objects.getObject('hm-rpc.meta.roles', function (err, res) {
            // Todo Handle Errors
            metaRoles = res.native;

            // Start Adapter
            if (adapter.config.init) {
                if (!rpcServerStarted) initRpcServer(adapter.config.type);
            }

        });
    });

}

function initRpcServer(type) {
    adapter.getPort(2000, function (port) {
        rpcServerStarted = true;
        var protocol = 'http://';
        if (type === 'bin') {
            var protocol = 'xmlrpc_bin://';
            rpcServer = binrpc.createServer({ host: adapter.config.adapterAddress, port: port });
        } else {
            rpcServer = xmlrpc.createServer({ host: adapter.config.adapterAddress, port: port });
        }

        log.info(type + 'rpc server listening on ' + adapter.config.adapterAddress + ':' + port);


        log.info(type + 'rpc -> ' + adapter.config.homematicAddress + ':' + adapter.config.homematicPort + ' init ' + JSON.stringify([protocol + adapter.config.adapterAddress + ':' + port, adapter.namespace]));

        rpcClient.methodCall('init', [protocol + adapter.config.adapterAddress + ':' + port, adapter.namespace], function (err, data) {
            if (!err) {
                connection();
            }
        });

        rpcServer.on('NotFound', function(method, params) {
            adapter.log.warn(type + 'rpc <- undefined method ' + method + ' ' + JSON.stringify(params).slice(0, 80));
        });

        rpcServer.on('system.multicall', function(method, params, callback) {
            var response = [];
            for (var i = 0; i < params[0].length; i++) {
                if (methods[params[0][i].methodName]) {
                    response.push(methods[params[0][i].methodName](null, params[0][i].params));
                } else {
                    response.push('');
                }
            }
            callback(null, response);
        });

        rpcServer.on('system.listMethods', function(err, params, callback) {
            adapter.log.info(adapter.config.type + 'rpc <- system.listMethods ' + JSON.stringify(params));
            callback(null, ['event', 'deleteDevices', 'listDevices', 'newDevices', 'system.listMethods', 'system.multicall']);
        });

        rpcServer.on('event', function(err, params, callback) {
            connection();
            callback(null, methods.event(err, params));
        });

        rpcServer.on('newDevices', function(err, params, callback) {
            var deviceArr = params[1];
            adapter.log.info(adapter.config.type + 'rpc <- newDevices ' + deviceArr.length);

            for (var i = 0; i < deviceArr.length; i++) {

                var type;
                var role;

                var children = [];

                if (deviceArr[i].PARENT) {
                    type = 'channel';
                    role = metaRoles.chTYPE && metaRoles.chTYPE[deviceArr[i].TYPE] ? metaRoles.chTYPE && metaRoles.chTYPE[deviceArr[i].TYPE] : undefined;
                } else {
                    type = 'device';
                    for (var j = 0; j < deviceArr[i].CHILDREN.length; j++) {
                        children.push(adapter.namespace + '.' + deviceArr[i].CHILDREN[j]);
                    }
                }

                var obj = {
                    type: type,
                    parent: (deviceArr[i].PARENT === '' ? null : adapter.namespace + '.' + deviceArr[i].PARENT),
                    children: children,
                    common: {},
                    native: deviceArr[i]
                };



                adapter.setObject(deviceArr[i].ADDRESS, obj);
                adapter.log.info('object ' + deviceArr[i].ADDRESS + ' created');

                if (obj.type === 'channel') {
                    var cid = obj.PARENT_TYPE + '.' + obj.TYPE + '.' + obj.VERSION;
                    channelParams[deviceArr[i].ADDRESS] = cid;
                    if (metaValues[cid]) {

                    } else {
                        queueValueParamsets.push(obj);
                    }
                }
            }
            getValueParamsets();
            callback(null, '');
        });

        rpcServer.on('listDevices', function(err, params, callback) {
            log.info(adapter.config.type + 'rpc <- listDevices ' + JSON.stringify(params));
            adapter.objects.getObjectView('hm-rpc', 'listDevices', {startkey: 'hm-rpc.' + adapter.instance + '.', endkey: 'hm-rpc.' + adapter.instance + '.\u9999'}, function (err, doc) {
                var response = [];
                for (var i = 0; i < doc.rows.length; i++) {
                    var val = doc.rows[i].value;
                    if (val.PARENT_TYPE) {
                        var cid = val.PARENT_TYPE + '.' + val.TYPE + '.' + val.VERSION;
                        channelParams[val.ADDRESS] = cid;
                    }
                    response.push({ADDRESS: val.ADDRESS, VERSION: val.VERSION});
                }
                log.info(adapter.config.type + 'rpc -> ' + doc.rows.length + ' devices');
                callback(null, response);
            });
        });

        rpcServer.on('deleteDevices', function(err, params, callback) {
            log.info(adapter.config.type + 'rpc <- deleteDevices ' + params[1].length);
            for (var i = 0; i < params[1].length; i++) {
                adapter.log.info('object ' + params[1][i].ADDRESS + ' deleted');
                adapter.delObject(params[1][i]);
            }
            callback(null, '');
        });
    });
}

var methods = {

    event: function (err, params) {
        log.debug(adapter.config.type + 'rpc <- event ' + JSON.stringify(params));
        adapter.setState(params[1]+'.'+params[2], {val: params[3], ack: true});
        return '';
    }

};

var queueValueParamsets = [];

function addParamsetObjects(channel, paramset) {
    var channelChildren = [];
    for (var key in paramset) {
        channelChildren.push(channel._id + '.' + key);
        var commonType = {
            'ACTION':       'boolean',
            'BOOL':         'boolean',
            'FLOAT':        'number',
            'ENUM':         'number',
            'INTEGER':      'number',
            'STRING':       'string'
        };

        var obj = {
            type: 'state',
            parent: channel._id,

            common: {
                def: paramset[key].DEFAULT,
                type: commonType[paramset[key].TYPE] || paramset[key].TYPE,
                read:   (paramset[key].OPERATIONS & 1 ? true : false),
                write:  (paramset[key].OPERATIONS & 2 ? true : false)
            },
            native: paramset[key]
        };

        if (obj.common.type === 'number') {
            obj.common.min = paramset[key].MIN;
            obj.common.max = paramset[key].MAX;

            if (paramset[key].TYPE === 'ENUM') {
                obj.common.states = {};
                for (var i = 0; i < paramset[key].VALUE_LIST.length; i++) {
                    obj.common.states[i] = paramset[key].VALUE_LIST[i];
                }
            }

            if (paramset[key].SPECIAL) {
                if (!obj.common.states) obj.common.states = {};
                for (var i = 0; i < paramset[key].SPECIAL.length; i++) {
                    obj.common.states[paramset[key].SPECIAL[i].VALUE] = paramset[key].SPECIAL[i].ID;
                }
            }

        }

        if (paramset[key].UNIT === '100%') {
            obj.common.unit = '%';
            obj.common.max = 100 * paramset[key].MAX;
        } else if (paramset[key].UNIT !== '') {
            obj.common.unit = paramset[key].UNIT;
        }

        if (metaRoles.dpCONTROL && metaRoles.dpCONTROL[obj.native.CONTROL]) {
            obj.common.role = metaRoles.dpCONTROL[obj.native.CONTROL];
        } else if (metaRoles.chTYPE_dpNAME && metaRoles.chTYPE_dpNAME[channel.native.TYPE + '.' + key]) {
            obj.common.role = metaRoles.chTYPE_dpNAME[channel.native.TYPE + '.' + key];
        } else if (metaRoles.dpNAME && metaRoles.dpNAME[key]) {
            obj.common.role = metaRoles.dpNAME[key];
        }


        if (paramset[key].OPERATIONS & 8) {
            obj.common.role = 'indicator.service'
        }

        adapter.log.info('object ' + channel.native.ADDRESS + '.' + key + ' created');
        adapter.setObject(channel.native.ADDRESS + '.' + key, obj, function () {

        });
    }
    adapter.extendObject(channel.native.ADDRESS, {children: channelChildren});
    adapter.log.info('object ' + channel.native.ADDRESS + ' extended');

}

function getValueParamsets() {
    if (queueValueParamsets.length === 0) {<commit_msg>queue device/channel/datapoint creation - fixes missing children<commit_after>var adapter = require(__dirname + '/../../lib/adapter.js')({

    name:                   'hm-rpc',

    ready: function () {
        adapter.subscribeStates('*');
        main();
    },
    stateChange: function (id, state) {
        if (state.ack !== true) {
            var tmp = id.split('.');
            adapter.log.debug(adapter.config.type + 'rpc -> setValue ' + JSON.stringify([tmp[2], tmp[3], state.val]));
            if (channelParams[tmp[2]] && metaValues[channelParams[tmp[2]]] && metaValues[channelParams[tmp[2]]][tmp[3]]) {
                if (!(metaValues[channelParams[tmp[2]]][tmp[3]].OPERATIONS & 2)) {
                    adapter.log.warn(adapter.config.type + 'rpc -> setValue ' + JSON.stringify([tmp[2], tmp[3], state.val]) + ' is not writeable');
                }
                var type = metaValues[channelParams[tmp[2]]][tmp[3]].TYPE;
            } else {
                var type = 'UNKNOWN';
            }
            if (metaValues[channelParams[tmp[2]]][tmp[3]].TYPE === '100%') {
                state.val = state.val / 100;
            }
            switch (type) {
                case 'BOOL':
                    var val = !!state.val;
                    break;
                case 'FLOAT':
                    var val = {explicitDouble: state.val};
                    break;
                default:
                    var val = state.val;
            }
            adapter.log.info('setValue ' + JSON.stringify([tmp[2], tmp[3], val]) + ' ' + type);
            rpcClient.methodCall('setValue', [tmp[2], tmp[3], val], function (err, data) {
                if (err) {
                    adapter.log.error(adapter.config.type + 'rpc -> setValue ' + JSON.stringify([tmp[2], tmp[3], state.val]));
                    adapter.log.error(err);
                }
            });
        }
    },
    //  - callback must be called in any case!
    unload: function (callback) {
        try {
            if (adapter.config.init) {
                adapter.config.init = false;
                log.info(adapter.config.type + "rpc -> " + adapter.config.homematicAddress + ':' + adapter.config.homematicPort + ' init ' + JSON.stringify(['http://' + adapter.config.adapterAddress + ':' + adapter.config.homematicPort, '']));
                rpcClient.methodCall('init', ['http://' + adapter.config.adapterAddress + ':' + adapter.config.homematicPort, ''], function (err, data) {
                    adapter.states.setState('system.adapter.' + adapter.namespace + '.connected', {val: false});
                    callback();
                });
            } else {
                callback();
            }
        } catch (e) {
            callback();
        }
    },
    install: function (callback) {
        var design = {
            "_id": "_design/hm-rpc",
            "language": "javascript",
            "views": {
                "listDevices": {
                    "map": "function(doc) {\n  if (doc._id.match(/^hm-rpc\\.[0-9]+\\.\\*?[A-Za-z0-9_-]+(:[0-9]+)?$/)) {\n   emit(doc._id, {ADDRESS:doc.native.ADDRESS,VERSION:doc.native.VERSION,PARENT_TYPE:doc.native.PARENT_TYPE,TYPE:doc.native.TYPE});\n  }\n}"
                },
                "paramsetDescription": {
                    "map": "function(doc) {\n  if (doc._id.match(/^hm-rpc\\.meta/) && doc.meta.type === 'paramsetDescription') {\n   emit(doc._id, doc);\n  }\n}"
                }
            }
        };
        adapter.objects.setObject(design._id, design, function () {
            log.info('object _design/hm-rpc created');
            if (typeof callback === 'function') callback();
        });
    }
});

var rpc;
var rpcClient;
var rpcClientPending;

var rpcServer;
var rpcServerStarted;

var connected;

var metaValues =    {};
var metaRoles =     {};
var channelParams = {};


var xmlrpc = require('xmlrpc');
var iconv = require('iconv-lite');

function main() {
    rpcClient = xmlrpc.createClient({
        host: adapter.config.homematicAddress,
        port: adapter.config.homematicPort,
        path: '/'
    });



    // Load VALUE paramsetDescriptions (needed to create state objects)
    adapter.objects.getObjectView('hm-rpc', 'paramsetDescription', {startkey: 'hm-rpc.meta.VALUES', endkey: 'hm-rpc.meta.VALUES.\u9999'}, function (err, doc) {
        // Todo Handle Errors
        var response = [];
        for (var i = 0; i < doc.rows.length; i++) {
            metaValues[doc.rows[i].id.slice(19)] = doc.rows[i].value.native;
        }
        // Load common.role assignments
        adapter.objects.getObject('hm-rpc.meta.roles', function (err, res) {
            // Todo Handle Errors
            metaRoles = res.native;

            // Start Adapter
            if (adapter.config.init) {
                if (!rpcServerStarted) initRpcServer(adapter.config.type);
            }

        });
    });

}

function initRpcServer(type) {
    adapter.getPort(2000, function (port) {
        rpcServerStarted = true;
        var protocol = 'http://';
        if (type === 'bin') {
            var protocol = 'xmlrpc_bin://';
            rpcServer = binrpc.createServer({ host: adapter.config.adapterAddress, port: port });
        } else {
            rpcServer = xmlrpc.createServer({ host: adapter.config.adapterAddress, port: port });
        }

        log.info(type + 'rpc server listening on ' + adapter.config.adapterAddress + ':' + port);


        log.info(type + 'rpc -> ' + adapter.config.homematicAddress + ':' + adapter.config.homematicPort + ' init ' + JSON.stringify([protocol + adapter.config.adapterAddress + ':' + port, adapter.namespace]));

        rpcClient.methodCall('init', [protocol + adapter.config.adapterAddress + ':' + port, adapter.namespace], function (err, data) {
            if (!err) {
                connection();
            }
        });

        rpcServer.on('NotFound', function(method, params) {
            adapter.log.warn(type + 'rpc <- undefined method ' + method + ' ' + JSON.stringify(params).slice(0, 80));
        });

        rpcServer.on('system.multicall', function(method, params, callback) {
            var response = [];
            for (var i = 0; i < params[0].length; i++) {
                if (methods[params[0][i].methodName]) {
                    response.push(methods[params[0][i].methodName](null, params[0][i].params));
                } else {
                    response.push('');
                }
            }
            callback(null, response);
        });

        rpcServer.on('system.listMethods', function(err, params, callback) {
            adapter.log.info(adapter.config.type + 'rpc <- system.listMethods ' + JSON.stringify(params));
            callback(null, ['event', 'deleteDevices', 'listDevices', 'newDevices', 'system.listMethods', 'system.multicall']);
        });

        rpcServer.on('event', function(err, params, callback) {
            connection();
            callback(null, methods.event(err, params));
        });

        rpcServer.on('newDevices', function(err, params, callback) {
            var deviceArr = params[1];
            adapter.log.info(adapter.config.type + 'rpc <- newDevices ' + deviceArr.length);

            var objs = [];

            for (var i = 0; i < deviceArr.length; i++) {

                var type;
                var role;

                var children = [];

                if (deviceArr[i].PARENT) {
                    type = 'channel';
                    role = metaRoles.chTYPE && metaRoles.chTYPE[deviceArr[i].TYPE] ? metaRoles.chTYPE && metaRoles.chTYPE[deviceArr[i].TYPE] : undefined;
                } else {
                    type = 'device';
                    for (var j = 0; j < deviceArr[i].CHILDREN.length; j++) {
                        children.push(adapter.namespace + '.' + deviceArr[i].CHILDREN[j]);
                    }
                }

                var obj = {
                    _id: deviceArr[i].ADDRESS,
                    type: type,
                    parent: (deviceArr[i].PARENT === '' ? null : adapter.namespace + '.' + deviceArr[i].PARENT),
                    children: children,
                    common: {
                        role: role
                    },
                    native: deviceArr[i]
                };

                objs.push(obj);

            }


            function queue() {
                if (objs.length > 1) {

                    var obj = objs.pop();
                    adapter.setObject(obj._id, obj, function (err, res) {
                        if (!err) {
                            adapter.log.info('object ' + res.id + ' created');
                        } else {
                            adapter.log.error('object ' + (res ? res.id : '?') + ' error on creation: ' + err);
                        }
                        queue();
                    });

                    if (obj.type === 'channel') {
                        var cid = obj.PARENT_TYPE + '.' + obj.TYPE + '.' + obj.VERSION;
                        channelParams[obj._id] = cid;
                        if (!metaValues[cid]) {
                            queueValueParamsets.push(obj);
                        }
                    }

                } else {
                    getValueParamsets();
                    callback(null, '');
                }
            }

            queue();

        });

        rpcServer.on('listDevices', function(err, params, callback) {
            log.info(adapter.config.type + 'rpc <- listDevices ' + JSON.stringify(params));
            adapter.objects.getObjectView('hm-rpc', 'listDevices', {startkey: 'hm-rpc.' + adapter.instance + '.', endkey: 'hm-rpc.' + adapter.instance + '.\u9999'}, function (err, doc) {
                var response = [];
                for (var i = 0; i < doc.rows.length; i++) {
                    var val = doc.rows[i].value;
                    if (val.PARENT_TYPE) {
                        var cid = val.PARENT_TYPE + '.' + val.TYPE + '.' + val.VERSION;
                        channelParams[val.ADDRESS] = cid;
                    }
                    response.push({ADDRESS: val.ADDRESS, VERSION: val.VERSION});
                }
                log.info(adapter.config.type + 'rpc -> ' + doc.rows.length + ' devices');
                callback(null, response);
            });
        });

        rpcServer.on('deleteDevices', function(err, params, callback) {
            log.info(adapter.config.type + 'rpc <- deleteDevices ' + params[1].length);
            for (var i = 0; i < params[1].length; i++) {
                adapter.log.info('object ' + params[1][i].ADDRESS + ' deleted');
                adapter.delObject(params[1][i]);
            }
            callback(null, '');
        });
    });
}

var methods = {

    event: function (err, params) {
        log.debug(adapter.config.type + 'rpc <- event ' + JSON.stringify(params));
        adapter.setState(params[1]+'.'+params[2], {val: params[3], ack: true});
        return '';
    }

};

var queueValueParamsets = [];

function addParamsetObjects(channel, paramset) {
    var channelChildren = [];
    for (var key in paramset) {
        channelChildren.push(channel._id + '.' + key);
        var commonType = {
            'ACTION':       'boolean',
            'BOOL':         'boolean',
            'FLOAT':        'number',
            'ENUM':         'number',
            'INTEGER':      'number',
            'STRING':       'string'
        };

        var obj = {
            type: 'state',
            parent: channel._id,

            common: {
                def:    paramset[key].DEFAULT,
                type:   commonType[paramset[key].TYPE] || paramset[key].TYPE,
                read:   (paramset[key].OPERATIONS & 1 ? true : false),
                write:  (paramset[key].OPERATIONS & 2 ? true : false)
            },
            native: paramset[key]
        };

        if (obj.common.type === 'number') {
            obj.common.min = paramset[key].MIN;
            obj.common.max = paramset[key].MAX;

            if (paramset[key].TYPE === 'ENUM') {
                obj.common.states = {};
                for (var i = 0; i < paramset[key].VALUE_LIST.length; i++) {
                    obj.common.states[i] = paramset[key].VALUE_LIST[i];
                }
            }

            if (paramset[key].SPECIAL) {
                if (!obj.common.states) obj.common.states = {};
                for (var i = 0; i < paramset[key].SPECIAL.length; i++) {
                    obj.common.states[paramset[key].SPECIAL[i].VALUE] = paramset[key].SPECIAL[i].ID;
                }
            }

        }

        if (paramset[key].UNIT === '100%') {
            obj.common.unit = '%';
            obj.common.max = 100 * paramset[key].MAX;
        } else if (paramset[key].UNIT !== '') {
            obj.common.unit = paramset[key].UNIT;
        }

        if (metaRoles.dpCONTROL && metaRoles.dpCONTROL[obj.native.CONTROL]) {
            obj.common.role = metaRoles.dpCONTROL[obj.native.CONTROL];

        } else if (metaRoles.chTYPE_dpNAME && metaRoles.chTYPE_dpNAME[channel.native.TYPE + '.' + key]) {
            obj.common.role = metaRoles.chTYPE_dpNAME[channel.native.TYPE + '.' + key];

        } else if (metaRoles.dpNAME && metaRoles.dpNAME[key]) {
            obj.common.role =  metaRoles.dpNAME[key];
        }


        if (paramset[key].OPERATIONS & 8) {
            obj.common.role = 'indicator.service';
        }

        if (typeof obj.common.role !== 'string' && typeof obj.common.role !== 'undefined') {
            throw 'typeof obj.common.role ' + typeof obj.common.role;
         }
        adapter.setObject(channel.native.ADDRESS + '.' + key, obj, function (err, res) {
            if (!err) {
                adapter.log.info('object ' + res.id + ' created');
            } else {
                adapter.log.error('object ' + (res ? res.id : '?') + ' create ' + err);
            }


        });
    }
    adapter.extendObject(channel.native.ADDRESS, {children: channelChildren}, function (err, res, id) {
        if (!err) {
            adapter.log.info('object ' + res.id + ' extended');
        } else {
            adapter.log.error('object ' + id + ' extend: ' + err);
        }
    });

}

function getValueParamsets() {
    if (queueValueParamsets.length === 0) {
{'fraction_non_alphanumeric': 0.1556538264746729, 'fraction_numerical': 0.005518602441342007, 'mean_word_length': 1.6277729760875828, 'pattern_counts': {'":': 14, '<': 31, '<?xml version=': 0, '>': 16, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 10}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1582188', 'n_tokens_mistral': 8049, 'n_tokens_neox': 7623, 'n_words': 1420}