function createRedisClient(clientConfig) {
  let c = require('config');
  let client = null;
  let conId = null;
  let conType = null;

  let redisOpts = {
    //showFriendlyErrorStack: true,
    db: clientConfig.dbIndex,
    username: clientConfig.username,
    password: clientConfig.password,
    connectionName: clientConfig.connectionName || c.get('redis.connectionName'),
    retryStrategy: function (times) {
      return times > 10 ? 3000 : 1000;
    }
  };

  if (clientConfig.optional) {
    redisOpts.retryStrategy = null;
  }

  // add tls support (simple and complex)
  // 1) boolean flag - simple tls without cert validation and similiar
  // 2) object - all params allowed for tls socket possible (see https://nodejs.org/api/tls.html#tls_tls_createsecurecontext_options)
  if (typeof clientConfig.tls === 'boolean' && clientConfig.tls) {
    redisOpts.tls = {};
  }
  else if (typeof clientConfig.tls === 'object') {
    redisOpts.tls = clientConfig.tls;
  }

  if (clientConfig.sentinels) {
    Object.assign(redisOpts, {
      sentinels: clientConfig.sentinels,
      name: getRedisSentinelGroupName(clientConfig.sentinelName),
      sentinelUsername: clientConfig.sentinelUsername || null,
      sentinelPassword: clientConfig.sentinelPassword || null
    });
    // add sentinel tls support (simple and complex)
    // 1) boolean flag - simple tls without cert validation and similiar
    // 2) object - all params allowed for tls socket possible (see https://nodejs.org/api/tls.html#tls_tls_createsecurecontext_options)
    if (typeof clientConfig.sentinelTLS === 'boolean' && clientConfig.sentinelTLS) {
      redisOpts.enableTLSForSentinelMode = true
      redisOpts.sentinelTLS = redisOpts.tls || {};
    }
    else if (typeof clientConfig.sentinelTLS === 'object') {
      redisOpts.enableTLSForSentinelMode = true
      redisOpts.sentinelTLS = clientConfig.sentinelTLS;
    }
    else {
      redisOpts.enableTLSForSentinelMode = false
    }
    conId = `S:${redisOpts.sentinels[0].host}:${redisOpts.sentinels[0].port}:${redisOpts.name}-${redisOpts.db}`;
    conType = 'sentinel';
  }
  else if (clientConfig.clusters || clientConfig.isCluster) {
    redisOpts = {
      scaleReads: clientConfig.clusterScaleReads || 'master',
      redisOptions: redisOpts
    }
    // clusters might not be set but isCluster only -> one server and port defined in normal redis parameter,
    // no full ist of clusters available. This might be triggered if connection to redis server is established
    // and active cluster config found
    // no create valid clusters list
    if (clientConfig.isCluster && !clientConfig.clusters) {
      clientConfig.clusters = [
        {host: clientConfig.host, port: clientConfig.port}
      ];
    }
    // special setup needed for AWS (and other?) where trying to connect to all nodes
    // a certificate error is thrown about certificate not holding IP addresses of nodes
    if (clientConfig.clusterNoTlsValidation && clientConfig.tls) {
      clientConfig.tls.rejectUnauthorized = false
    }

    // cluster does not support SELECT command and different DBs, forced set to 0
    redisOpts.redisOptions.db = 0

    conId = `C:${clientConfig.clusters[0].host}:${clientConfig.clusters[0].port}:${redisOpts.redisOptions.db}`;
    conType = 'cluster';
  }
  else {
    Object.assign(redisOpts, {
      port: clientConfig.port,
      host: clientConfig.host,
      path: clientConfig.path,
      family: 0
    });
    if (clientConfig.path) {
      // unix-socket:
      // no need for strong crypto here, just short string hopefully unique between different socket paths
      // only needed if someone uses this app with multiple different local redis sockets...
      // ATTN: use no hardcoded algorithm as some systems may not support it. just search for a sha-something
      let hashAlg = crypto.getHashes().find((h) => (h.startsWith('sha')));
      let cid =crypto.createHash(hashAlg).update(clientConfig.path).digest('hex').substring(24);
      conId = `U:${cid}:${redisOpts.db}`;
      conType = 'socket';
    }
    else {
      conId = `R:${redisOpts.host}:${redisOpts.port}:${redisOpts.db}`;
      conType = 'standalone';
    }
  }
  if (conType === 'cluster') {
    client = new Redis.Cluster(clientConfig.clusters, redisOpts);
    client.options.clusters = clientConfig.clusters;
    client.options.db = redisOpts.redisOptions.db;
    if (redisOpts.redisOptions.tls) client.options.tls = redisOpts.redisOptions.tls;
  }
  else {
    client = new Redis(redisOpts);
  }

  client.label = clientConfig.label;
  Object.assign(client.options, {
    connectionId: clientConfig.connectionId = conId,
    type: conType,
    foldingChar: clientConfig.foldingChar || c.get('ui.foldingChar'),
    clusterNoTlsValidation: clientConfig.clusterNoTlsValidation
  });
  if (clientConfig.optional) client.options.isOptional = true;
  return client;
}
Function to create a new redis client object by given parameter
 This one is used by creating clients at startup from command line, config file
 or new connections added via UI during runtime.
 The redis client created can be either a normal redis client or a sentinel client, base on
 configuration given.

 @param {object} clientConfig - configuration to create client from