main.js
/**
     * processMsg
     *
     * Processes the current received message and updates relevant data fields
     *
     * @param device  {object} additional data for the current device which are not provided by Web-API (IP-Address, MQTT-Password)
     * @param path    {string} Additional subfolders can be given here if needed with a leading dot (eg. .Sensor)!
     * @param message {object} Current State of the device. Message is send by device via mqtt due to request or state change.
     */
processMsg
Processes the current received message and updates relevant data fields

@param device  {object} additional data for the current device which are not provided by Web-API (IP-Address, MQTT-Password)
@param path    {string} Additional subfolders can be given here if needed with a leading dot .
@param message {object} Current State of the device. Message is send by device via mqtt due to request or state change.
processMsg Processes the current received message and updates relevant data fields @param device { object } additional data for the current device which are not provided by Web - API ( IP - Address MQTT - Password ) @param path { string } Additional subfolders can be given here if needed with a leading dot . @param message { object } Current State of the device . Message is send by device via mqtt due to request or state change .
async processMsg( device, path, message ) {
        for (const row in message){
            if ( row === 'product-state'){
                await this.processMsg(device, '', message[row]);
                continue;
            }
            if ( row === 'data'){
                await this.processMsg(device, '.Sensor', message[row]);
                if (Object.prototype.hasOwnProperty.call(message[row], 'pm25')) {
                    this.createPM25(message, row, device);
                }
                if (Object.prototype.hasOwnProperty.call(message[row], 'pm10')) {
                    this.createPM10(message, row, device);
                }
                if (Object.prototype.hasOwnProperty.call(message[row], 'pact')) {
                    this.createDust(message, row, device);
                }
                if (Object.prototype.hasOwnProperty.call(message[row], 'va10')) {
                    this.createVOC(message, row, device);
                }
                if (Object.prototype.hasOwnProperty.call(message[row], 'noxl')) {
                    this.createNO2(message, row, device);
                }
                continue;
            }
            this.log.debug('Processing Message: ' + ((typeof message === 'object')? JSON.stringify(message) : message) );
            const deviceConfig = await this.getDatapoint(row);
            if ( deviceConfig === undefined){
                this.log.debug('Skipped creating unknown data field for: [' + row + '] Value: |-> ' + ((typeof( message[row] ) === 'object')? JSON.stringify(message[row]) : message[row]) );
                continue;
            }
            let value;
            if (deviceConfig[3]==='number'){
                value = Number.parseInt(message[deviceConfig[0]], 10);
                if (deviceConfig[5] === 'value.temperature') {
                    switch (this.config.temperatureUnit) {
                        case 'K' : value /= 10;
                            break;
                        case 'C' :
                            deviceConfig[6] = '°' + this.config.temperatureUnit;
                            value = Number((value/10) - 273.15).toFixed(2);
                            break;
                        case 'F' :
                            deviceConfig[6] = '°' + this.config.temperatureUnit;
                            value = Number(((value/10) - 273.15) * (9/5) + 32).toFixed(2);
                            break;
                    }
                }
                if (deviceConfig[0] === 'filf') {
                    value = Number(value * 100/4300);
                    this.createOrExtendObject( device.Serial + path + '.FilterLifePercent', { type: 'state', common: {name: deviceConfig[2], 'read':true, 'write': deviceConfig[4]==='true', 'role': deviceConfig[5], 'type':deviceConfig[3], 'unit':'%', 'states': deviceConfig[7]}, native: {} }, value);
                }
            } else {
                value = message[deviceConfig[0]];
            }
            if (typeof (value) === 'object') {
                if (value[0] === value[1]) {
                    this.log.debug('Values for [' + deviceConfig[1] + '] are equal. No update required. Skipping.');
                } else {
                    value = value[1];
                }
            }
            if (deviceConfig.length > 7) {
                this.createOrExtendObject( device.Serial + path + '.'+ deviceConfig[1], { type: 'state', common: {name: deviceConfig[2], 'read':true, 'write': deviceConfig[4]==='true', 'role': deviceConfig[5], 'type':deviceConfig[3], 'unit':deviceConfig[6], 'states': deviceConfig[7]}, native: {} }, value);
            } else {
                this.createOrExtendObject( device.Serial + path + '.'+ deviceConfig[1], { type: 'state', common: {name: deviceConfig[2], 'read':true, 'write': deviceConfig[4]==='true', 'role': deviceConfig[5], 'type':deviceConfig[3], 'unit':deviceConfig[6] }, native: {} }, value);
            }
            if (deviceConfig[4]==='true') {
                this.log.debug('Subscribing for state changes on :' + device.Serial + path + '.'+ deviceConfig[1] );
                this.subscribeStates(device.Serial + path + '.'+ deviceConfig[1] );
            }
        }
    }
async processMsg ( device , path , message ) { for ( const row in message ) { if ( row === 'product-state' ) { await this . processMsg ( device , '' , message [ row ] ) ; continue ; } if ( row === 'data' ) { await this . processMsg ( device , '.Sensor' , message [ row ] ) ; if ( Object . prototype . hasOwnProperty . call ( message [ row ] , 'pm25' ) ) { this . createPM25 ( message , row , device ) ; } if ( Object . prototype . hasOwnProperty . call ( message [ row ] , 'pm10' ) ) { this . createPM10 ( message , row , device ) ; } if ( Object . prototype . hasOwnProperty . call ( message [ row ] , 'pact' ) ) { this . createDust ( message , row , device ) ; } if ( Object . prototype . hasOwnProperty . call ( message [ row ] , 'va10' ) ) { this . createVOC ( message , row , device ) ; } if ( Object . prototype . hasOwnProperty . call ( message [ row ] , 'noxl' ) ) { this . createNO2 ( message , row , device ) ; } continue ; } this . log . debug ( 'Processing Message: ' + ( ( typeof message === 'object' ) ? JSON . stringify ( message ) : message ) ) ; const deviceConfig = await this . getDatapoint ( row ) ; if ( deviceConfig === undefined ) { this . log . debug ( 'Skipped creating unknown data field for: [' + row + '] Value: |-> ' + ( ( typeof ( message [ row ] ) === 'object' ) ? JSON . stringify ( message [ row ] ) : message [ row ] ) ) ; continue ; } let value ; if ( deviceConfig [ 3 ] === 'number' ) { value = Number . parseInt ( message [ deviceConfig [ 0 ] ] , 10 ) ; if ( deviceConfig [ 5 ] === 'value.temperature' ) { switch ( this . config . temperatureUnit ) { case 'K' : value /= 10 ; break ; case 'C' : deviceConfig [ 6 ] = '°'  his. c onfig. t emperatureUnit; value = Number ( ( value / 10 ) - 273.15 ) . toFixed ( 2 ) ; break ; case 'F' : deviceConfig [ 6 ] = '°'  his. c onfig. t emperatureUnit; value = Number ( ( ( value / 10 ) - 273.15 ) * ( 9 / 5 ) + 32 ) . toFixed ( 2 ) ; break ; } } if ( deviceConfig [ 0 ] === 'filf' ) { value = Number ( value * 100 / 4300 ) ; this . createOrExtendObject ( device . Serial + path + '.FilterLifePercent' , { type : 'state' , common : { name : deviceConfig [ 2 ] , 'read' : true , 'write' : deviceConfig [ 4 ] === 'true' , 'role' : deviceConfig [ 5 ] , 'type' : deviceConfig [ 3 ] , 'unit' : '%' , 'states' : deviceConfig [ 7 ] } , native : { } } , value ) ; } } else { value = message [ deviceConfig [ 0 ] ] ; } if ( typeof ( value ) === 'object' ) { if ( value [ 0 ] === value [ 1 ] ) { this . log . debug ( 'Values for [' + deviceConfig [ 1 ] + '] are equal. No update required. Skipping.' ) ; } else { value = value [ 1 ] ; } } if ( deviceConfig . length > 7 ) { this . createOrExtendObject ( device . Serial + path + '.' + deviceConfig [ 1 ] , { type : 'state' , common : { name : deviceConfig [ 2 ] , 'read' : true , 'write' : deviceConfig [ 4 ] === 'true' , 'role' : deviceConfig [ 5 ] , 'type' : deviceConfig [ 3 ] , 'unit' : deviceConfig [ 6 ] , 'states' : deviceConfig [ 7 ] } , native : { } } , value ) ; } else { this . createOrExtendObject ( device . Serial + path + '.' + deviceConfig [ 1 ] , { type : 'state' , common : { name : deviceConfig [ 2 ] , 'read' : true , 'write' : deviceConfig [ 4 ] === 'true' , 'role' : deviceConfig [ 5 ] , 'type' : deviceConfig [ 3 ] , 'unit' : deviceConfig [ 6 ] } , native : { } } , value ) ; } if ( deviceConfig [ 4 ] === 'true' ) { this . log . debug ( 'Subscribing for state changes on :' + device . Serial + path + '.' + deviceConfig [ 1 ] ) ; this . subscribeStates ( device . Serial + path + '.' + deviceConfig [ 1 ] ) ; } } }
processMsg
 Processes the current received message and updates relevant data fields
processMsg Processes the current received message and updates relevant data fields
// Is this a "product-state" message? // Is this a "data" message? // Handle all other message types // strip leading zeros from numbers // convert temperature to configured unit // create additional data field filterlifePercent converting value from hours to percent; 4300 is the estimated lifetime in hours by dyson // during state-change message only changed values are being updated // deviceConfig.length>7 means the data field has predefined states attached, that need to be handled // deviceConfig[4]=true -> data field is editable, so subscribe for state changes