Skip to content
  • Home
  • Aktuell
  • Tags
  • 0 Ungelesen 0
  • Kategorien
  • Unreplied
  • Beliebt
  • GitHub
  • Docu
  • Hilfe
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Standard: (Kein Skin)
  • Kein Skin
Einklappen
ioBroker Logo

Community Forum

donate donate
  1. ioBroker Community Home
  2. Deutsch
  3. Tester
  4. Adapter Hyundai (Bluelink) oder KIA (UVO)

NEWS

  • UPDATE 31.10.: Amazon Alexa - ioBroker Skill läuft aus ?
    apollon77A
    apollon77
    48
    3
    8.5k

  • Monatsrückblick – September 2025
    BluefoxB
    Bluefox
    13
    1
    2.1k

  • Neues Video "KI im Smart Home" - ioBroker plus n8n
    BluefoxB
    Bluefox
    16
    1
    2.7k

Adapter Hyundai (Bluelink) oder KIA (UVO)

Geplant Angeheftet Gesperrt Verschoben Tester
2.3k Beiträge 151 Kommentatoren 877.6k Aufrufe 140 Watching
  • Älteste zuerst
  • Neuste zuerst
  • Meiste Stimmen
Antworten
  • In einem neuen Thema antworten
Anmelden zum Antworten
Dieses Thema wurde gelöscht. Nur Nutzer mit entsprechenden Rechten können es sehen.
  • S stefan.cloer

    @arteck
    Ich habe dann Anfang der Woche auch mal den Wechsel von meiner selbst angepassten "main.js" des Adapters auf die Version 2.2.8 gemacht. Ich habe also die 2.2.7 übersprungen.
    Nach der Installation von 2.2.8 funktionierte die Abfrage des Autos leider bei mir auch nicht mehr so schön wie sie zuvor bei meiner selbst gemachten Anpassung lief. Ich hatte auch sehr schnell den Verdacht, dass sich in der 2.2.8 ein Fehler befindet oder zumindest etwas anders lief als bei meiner eigenen Version. Daraufhin habe ich mal die neue "main.js" durchgeackert und tatsächlich ein paar Dinge gefunden die meiner Meinung nach nicht korrekt sind bzw. aus meiner Sicht besser gelöst werden könnten. (Das soll keine Kritik an der tollen Arbeit von @arteck und @Newan sein, ich hatte einfach nur gemerkt, dass sich da was anders verhält als zuvor.)
    Ich habe daraufhin noch mal ein paar Anpassungen an der "main.js" der Version 2.2.8 vorgenommen. Jetzt läuft sie wieder zu meiner vollsten Zufriedenheit. Gerne kann ich das mit euch teilen:

    'use strict';
    
    const utils = require('@iobroker/adapter-core');
    const bluelinky = require('bluelinky');
    const Json2iob = require('./lib/json2iob');
    let force_update = {};   
    force_update.val = true;   
    
    const adapterIntervals = {}; //halten von allen Intervallen
    let request_count = 48; // halbstündig sollte als Standardeinstellung reichen (zu häufige Abfragen entleeren die Batterie spürbar)
    let client;
    
    let slow_charging;
    let fast_charging;
    
    const POSSIBLE_CHARGE_LIMIT_VALUES = [50, 60, 70, 80, 90, 100];
    
    class Bluelink extends utils.Adapter {
        /**
         * @param {Partial<utils.AdapterOptions>} [options={}]
         */
        constructor(options) {
            super({
                ...options,
                name: 'bluelink',
            });
    
            this.on('ready', this.onReady.bind(this));
            this.on('stateChange', this.onStateChange.bind(this));
            // this.on('objectChange', this.onObjectChange.bind(this));
            // this.on('message', this.onMessage.bind(this));
            this.on('unload', this.onUnload.bind(this));
            this.vehiclesDict = {};
            this.batteryState12V = {};
            this.vehicles = [];
            this.json2iob = new Json2iob(this);
            adapterIntervals.evHistoryInterval = null;
            this.countError = 0;
        }
    
        //Start Adapter
        async onReady() {
            //first check account settings
            if (this.config.request < 1) {
                this.log.warn('Request is under 1 -> got to default 100');
            } else {
                request_count = this.config.request;
            }
    
            if (this.config.username == '') {
                this.log.error('No Username set');
            } else {
                //Start logic with login
                this.login();
            }
        }
    
        /**
         * Is called when adapter shuts down - callback has to be called under any circumstances!
         * @param {() => void} callback
         */
        onUnload(callback) {
            try {
                clearTimeout(adapterIntervals.readAllStates);
                clearInterval(adapterIntervals.evHistoryInterval);
                this.log.info('Adapter bluelink cleaned up everything...');
                callback();
            } catch (e) {
                callback();
            }
        }
    
        async onStateChange(id, state) {
            if (state) {
                if (id.indexOf('.control.') === -1) {
                    return;
                }
                this.log.debug('New Event for state: ' + JSON.stringify(state));
                this.log.debug('ID: ' + JSON.stringify(id));
    
                const vin = id.split('.')[2];
                const vehicle = this.vehiclesDict[vin];
                const tmpControl = id.split('.')[4];
                let response;
                switch (tmpControl) {
                    case 'lock':
                        this.log.info('Starting lock for vehicle');
                        response = await vehicle.lock();
                        this.log.info(response);
                        break;
                    case 'unlock':
                        this.log.info('Starting unlock for vehicle');
                        response = await vehicle.unlock();
                        this.log.info(response);
                        break;
                    case 'start':
                        this.log.info('Starting clima for vehicle');
    
                        let airCtrl = await this.getStateAsync(`${vin}.control.set.airCtrl`);                
                        let airTempC = await this.getStateAsync(`${vin}.control.set.airTemp`);
                        let airTempF = (airTempC.val * 9/5) + 32;
                        let defrost = await this.getStateAsync(`${vin}.control.set.defrost`);
                        let heating = await this.getStateAsync(`${vin}.control.set.heating`);
                      
                        try {
                            response = await vehicle.start({
                                airCtrl: airCtrl.val,
                                igniOnDuration: 10,
                                airTempvalue: airTempF,
                                defrost: defrost.val,
                                heating1: heating.val,
                            });
                        } catch (err) {
                            this.log.error(JSON.stringify(err));                    
                        }    
                        break;
                    case 'stop':
                        this.log.info('Stop clima for vehicle');
                        response = await vehicle.stop();
                        this.log.debug(JSON.stringify(response));
                        break;
                    case 'force_refresh':
                        this.log.info('Forcing refresh');
                        //Force refresh for new states
                        this.readStatus(true);
                        break;
                    case 'force_update':
    			        force_update = await this.getStateAsync(`${vin}.control.force_update`);   
    	            	if(force_update.val) {
        	                this.log.info('Update method for ' + vin + ' changed to "directly from the car"');
            	        } else {
                	        this.log.info('Update method for ' + vin + ' changed to "from the server"');
                    	}
                        break;
                    case 'charge':
                        this.log.info('Start charging');
                        response = await vehicle.startCharge();
                        break;
                    case 'charge_stop':
                        this.log.info('Stop charging');
                        response = await vehicle.stopCharge();
                        break;
                    case 'battery':
                        if (!state.ack) {
                            if (!POSSIBLE_CHARGE_LIMIT_VALUES.includes(state.val)) {
                                this.log.error(`Charge target values are limited to ${POSSIBLE_CHARGE_LIMIT_VALUES.join(', ')}`);
                            } else {
                                this.log.info('Set new charging options');
                                const charge_option = { fast: fast_charging, slow: slow_charging };
                                if (tmpControl[4] == 'charge_limit_fast') {
                                    //set fast charging
                                    this.log.debug('Set fast charging');
                                    charge_option.fast = state.val;
                                } else {
                                    //set slow charging
                                    this.log.debug('Set slow charging');
                                    charge_option.slow = state.val;
                                }
                                response = await vehicle.setChargeTargets(charge_option);
                                this.log.debug(JSON.stringify(response));
                            }
                        }
                        break;
                    default:
                        this.log.error('No command for Control found for: ' + id);
                }
            }
        }
    
        /**
         * Funktion to login in bluelink / UVO
         */
        login() {
            try {
                this.log.info('Login to api');
                const tmpConfig = {
                    username: this.config.username,
                    password: this.config.client_secret,
                    pin: this.config.client_secret_pin,
                    brand: this.config.brand,
                    region: 'EU', //set over GUI next time
                    language:  this.config.language,
                };
    
                // @ts-ignore
                client = new bluelinky(tmpConfig);
    
                client.on('ready', async (vehicles) => {
                    // wir haben eine Verbindung und haben Autos
                    this.log.info(vehicles.length + ' Vehicles found');
                    this.log.debug(JSON.stringify(vehicles, this.getCircularReplacer()));
    
                    this.vehicles = vehicles;
                    for (const vehicle of vehicles) {
                        const vin = vehicle.vehicleConfig.vin;
                        this.vehiclesDict[vin] = vehicle;
                        await this.setObjectNotExistsAsync(vin, {
                            type: 'device',
                            common: {
                                name: vehicle.vehicleConfig.nickname,
                            },
                            native: {},
                        });
    
                        await this.setControlObjects(vin);
                        await this.setStatusObjects(vin);
    
                        await this.setObjectNotExistsAsync(vin + '.general', {
                            type: 'channel',
                            common: {
                                name: 'General Information',
                            },
                            native: {},
                        });
                        await this.json2iob.parse(vin + '.general', vehicle.vehicleConfig);
                        if (this.config.evHistory) {
                            await this.receiveEVInformation(vehicle, vin);
                            adapterIntervals.evHistoryInterval = setInterval(() => {
                                this.receiveEVInformation(vehicle, vin);
                            }, 24 * 60 * 60 * 1000); //24h
                        }
                    }
                    //start time cycle
                    await this.readStatus();
    
                    //clean legacy states
                    this.cleanObjects();
                });
    
                client.on('error', async (err) => {
                    // something went wrong with login
                    this.log.debug('Error on Api login');
                    this.log.error(err);
                    this.log.error('Please logout in the app and relogin in the app');
                });
            } catch (error) {
                this.log.error('Error in login/on function');
                if (typeof error === 'string') {
                    this.log.error(error);
                } else if (error instanceof Error) {
                    this.log.error(error.message);
                }
            }
        }
    
        //read new sates from vehicle
        async readStatus(force = false) {
            //read new verhicle status
            for (const vehicle of this.vehicles) {
                const vin = vehicle.vehicleConfig.vin;
    
                this.log.debug('Read new status from api for ' + vin);
                if (this.batteryState12V[vin] && this.batteryState12V[vin] < 60) {
                    this.log.warn('12V Battery state is low: ' + this.batteryState12V[vin] + '%. Recharge to prevent damage!');
                    if (this.config.protectAgainstDeepDischarge && !force) {
                        this.log.warn('Auto Refresh is disabled, only use force refresh to reenable refresh if you are willing to risk your battery');
                        continue;
                    }
                }
                try {
                    let newStatus;
    
                	if(force_update.val) {
                        this.log.info('Read new update for ' + vin + ' directly from the car');
                    } else {
                        this.log.info('Read new update for ' + vin + ' from the server');
                    }
                    	
                	try {
                        newStatus = await vehicle.fullStatus({
                            refresh: force_update.val,
                            parsed: true,
                        });
                        //set all values
                        this.log.debug('Set new full status for ' + vin);
                        this.log.debug('RAW ' + JSON.stringify(newStatus));
                        
                        // raw data
                        await this.json2iob.parse(vin + '.vehicleStatusRaw', newStatus);
                        
                        await this.setNewFullStatus(newStatus, vin);
                        if (newStatus.vehicleStatus && newStatus.vehicleStatus.battery && newStatus.vehicleStatus.battery.batSoc) {
                            this.log.debug('Set ' + newStatus.vehicleStatus.battery.batSoc + ' battery state for ' + vin);
                            this.batteryState12V[vin] = newStatus.vehicleStatus.battery.batSoc;
                        }
    
                    } catch (error) {
                        if (typeof error === 'string') {
                            this.log.error('Error on API-Request GetFullStatus');
                            this.log.error(error);
                            //TODO option abfragen
                        } else {
                            //if(error.source.statusCode == 503) {
                            this.log.info('Error on API-Full-Status - Fallback GetNormalStatus');
    
                            //Abfrage Full hat nicht gekalppt. Haben wir einen Fallback?
                            newStatus = await vehicle.status({
                                refresh: force_update.val,
                                parsed: true,
                            });
                        	this.log.debug('Set new GetNormalStatus for ' + vin);
                            this.log.debug(JSON.stringify(newStatus));
    
                            await this.setNewStatus(newStatus, vin);
                            if (newStatus.engine && newStatus.engine.batteryCharge12v) {
                                this.log.debug('Set ' + newStatus.engine.batteryCharge12v + ' battery state for ' + vin);
                                this.batteryState12V[vin] = newStatus.engine.batteryCharge12v;
                            }
                        }
                    }
    
                    //Abfrage war erfolgreich, lösche ErrorCounter
                    this.countError = 0;
    
    		        force_update = await this.getStateAsync(`${vin}.control.force_update`);
                    this.log.info('Update for ' + vin + ' successfull');
    	  	       // last update
        	        await this.setStateAsync(`${vin}.lastInfoUpdate`, Number(Date.now()), true);
                
                } catch (error) {
                    this.countError += 1;  // add 1
                   
                    this.log.error('Error on API-Request Status, ErrorCount:' + this.countError);
                    if (typeof error === 'string') {
                        this.log.error(error);
                    } else if (error instanceof Error) {
                        this.log.error(error.message);
                    }
                }
    
                await this.setStateAsync(`${vin}.error_counter`, this.countError, true);
                
                if (this.countError > this.config.errorCounter) {
                    //Error counter over x erros, restart Adapter to fix te API Token
                    this.restart();
                }
            }
        
            //set ne cycle
            if (force) {
                clearTimeout(adapterIntervals.readAllStates);
            }
            adapterIntervals.readAllStates = setTimeout(this.readStatus.bind(this), ((24 * 60) / request_count) * 60000);
        }
    
        async receiveEVInformation(vehicle, vin) {
            try {
                const driveHistory = await vehicle.driveHistory();
                this.log.debug('driveHistory-Data: ' + JSON.stringify(driveHistory));
                
                if (driveHistory != undefined) { 
                
                    await this.setObjectNotExistsAsync(vin + '.driveHistory', {
                        type: 'channel',
                        common: {
                            name: 'drive history',
                        },
                        native: {},
                    });
                    await this.json2iob.parse(vin + '.driveHistory', driveHistory, { preferedArrayName: 'rawDate' });
                    const monthlyReport = await vehicle.monthlyReport();
                    await this.setObjectNotExistsAsync(vin + '.monthlyReport', {
                        type: 'channel',
                        common: {
                            name: 'monthly report',
                        },
                        native: {},
                    });
                    await this.json2iob.parse(vin + '.monthlyReport', monthlyReport);
                    const tripInfo = await vehicle.tripInfo({ year: new Date().getFullYear(), month: new Date().getMonth() + 1 });
                    await this.setObjectNotExistsAsync(vin + '.tripInfo', {
                        type: 'channel',
                        common: {
                            name: 'trip information',
                        },
                        native: {},
                    });
                    await this.json2iob.parse(vin + '.tripInfo', tripInfo);
                }
            } catch (error) {
                this.log.error('EV History fetching failed');
                if (typeof error === 'string') {
                    this.log.error(error);
                } else if (error instanceof Error) {
                    this.log.error(error.message);
                }
            }
        }
    
        //Set new values to ioBroker for normal Status
        async setNewStatus(newStatus, vin) {
            //chassis
            await this.setStateAsync(vin + '.vehicleStatus.doorLock', { val: newStatus.chassis.locked, ack: true });
            await this.setStateAsync(vin + '.vehicleStatus.trunkOpen', { val: newStatus.chassis.trunkOpen, ack: true });
            await this.setStateAsync(vin + '.vehicleStatus.hoodOpen', { val: newStatus.chassis.hoodOpen, ack: true });
    
            //chassis/doors
            this.checkDoor(vin, newStatus.chassis.openDoors);
    
            //chassis/tirePressure
         //   if (newStatus.chassis.tirePressureWarningLamp != undefined) {
         //
         //   }
    
            //climate
            await this.setStateAsync(vin + '.vehicleStatus.airCtrlOn', { val: newStatus.climate.active, ack: true });
            await this.setStateAsync(vin + '.vehicleStatus.airTemp', { val: newStatus.climate.temperatureSetpoint, ack: true });
            await this.setStateAsync(vin + '.vehicleStatus.steerWheelHeat', { val: newStatus.climate.steeringwheelHeat, ack: true });
            //await this.setStateAsync(vin + '.vehicleStatus.sideBackWindowHeat', { val: newStatus.climate.sideBackWindowHeat, ack: true });
    
            //Engine
            await this.setStateAsync(vin + '.vehicleStatus.battery.soc', { val: newStatus.engine.batteryChargeHV, ack: true });
            await this.setStateAsync(vin + '.vehicleStatus.battery.charge', { val: newStatus.engine.charging, ack: true });       
            await this.setStateAsync(vin + '.vehicleStatus.battery.soc-12V', { val: newStatus.engine.batteryCharge12v, ack: true });
        }
    
        //Set new values to ioBroker
        async setNewFullStatus(newStatus, vin) {
            await this.setStateAsync(vin + '.vehicleStatus.airCtrlOn', { val: newStatus.vehicleStatus.airCtrlOn, ack: true });
            await this.setStateAsync(vin + '.vehicleStatus.airTemp', {
                val: this.getCelsiusFromTempcode(newStatus.vehicleStatus.airTemp.value),
                ack: true,
            });
    
            //Charge
    
            //Bei Kia sind die Werte in einer targetSOClist
            if (newStatus.vehicleStatus.evStatus != undefined) {
                if (newStatus.vehicleStatus.evStatus.reservChargeInfos.targetSOClist != undefined) {
                    if (newStatus.vehicleStatus.evStatus.reservChargeInfos.targetSOClist[0].plugType == 1) {
                        //Slow  = 1  -> Index 0 ist slow
                        await this.setStateAsync(vin + '.vehicleStatus.battery.charge_limit_slow', {
                            val: newStatus.vehicleStatus.evStatus.reservChargeInfos.targetSOClist[0].targetSOClevel,
                            ack: true,
                        });
                        slow_charging = newStatus.vehicleStatus.evStatus.reservChargeInfos.targetSOClist[0].targetSOClevel;
                        await this.setStateAsync(vin + '.vehicleStatus.battery.charge_limit_fast', {
                            val: newStatus.vehicleStatus.evStatus.reservChargeInfos.targetSOClist[1].targetSOClevel,
                            ack: true,
                        });
                        fast_charging = newStatus.vehicleStatus.evStatus.reservChargeInfos.targetSOClist[1].targetSOClevel;
                    } else {
                        //fast  = 0  -> Index 0 ist fast
                        await this.setStateAsync(vin + '.vehicleStatus.battery.charge_limit_slow', {
                            val: newStatus.vehicleStatus.evStatus.reservChargeInfos.targetSOClist[1].targetSOClevel,
                            ack: true,
                        });
                        slow_charging = newStatus.vehicleStatus.evStatus.reservChargeInfos.targetSOClist[1].targetSOClevel;
                        await this.setStateAsync(vin + '.vehicleStatus.battery.charge_limit_fast', {
                            val: newStatus.vehicleStatus.evStatus.reservChargeInfos.targetSOClist[0].targetSOClevel,
                            ack: true,
                        });
                        fast_charging = newStatus.vehicleStatus.evStatus.reservChargeInfos.targetSOClist[0].targetSOClevel;
                    }
                } else {
                    //Bei Hyundai sieht es anders aus:
                }
    
                //Nur für Elektro Fahrzeuge - Battery
                await this.setStateAsync(vin + '.vehicleStatus.dte', {
                    val: newStatus.vehicleStatus.evStatus.drvDistance[0].rangeByFuel.totalAvailableRange.value,
                    ack: true,
                });
                await this.setStateAsync(vin + '.vehicleStatus.evModeRange', {
                    val: newStatus.vehicleStatus.evStatus.drvDistance[0].rangeByFuel.evModeRange.value,
                    ack: true,
                });
                if (newStatus.vehicleStatus.evStatus.drvDistance[0].rangeByFuel.gasModeRange != undefined) {
                    //Only for PHEV
                    await this.setStateAsync(vin + '.vehicleStatus.gasModeRange', {
                        val: newStatus.vehicleStatus.evStatus.drvDistance[0].rangeByFuel.gasModeRange.value,
                        ack: true,
                    });
                }
    
                await this.setStateAsync(vin + '.vehicleStatus.battery.soc', { val: newStatus.vehicleStatus.evStatus.batteryStatus, ack: true });
                await this.setStateAsync(vin + '.vehicleStatus.battery.charge', { val: newStatus.vehicleStatus.evStatus.batteryCharge, ack: true });
                await this.setStateAsync(vin + '.vehicleStatus.battery.plugin', { val: newStatus.vehicleStatus.evStatus.batteryPlugin, ack: true });
    
                //Ladezeit anzeigen, da noch nicht klar welche Werte
                await this.setStateAsync(vin + '.vehicleStatus.battery.minutes_to_charged', {
                    val: newStatus.vehicleStatus.evStatus.remainTime2.atc.value,
                    ack: true,
                });
                this.log.debug('Folgende Ladezeiten Moeglichkeiten wurden gefunden:');
                this.log.debug(JSON.stringify(newStatus.vehicleStatus.evStatus.remainTime2));
            } else {
                //Kein Elektromodell, Diesel etc
                await this.setStateAsync(vin + '.vehicleStatus.dte', { val: newStatus.vehicleStatus.dte.value, ack: true });
            }
    
            // nur für Kia              
            if (newStatus.vehicleStatus.battery != undefined) {
                await this.setStateAsync(vin + '.vehicleStatus.battery.soc-12V', { val: newStatus.vehicleStatus.battery.batSoc, ack: true });
                await this.setStateAsync(vin + '.vehicleStatus.battery.state-12V', { val: newStatus.vehicleStatus.battery.batState, ack: true });
            }
    
            //Location
            if (newStatus.vehicleLocation != undefined) {
                //#47 KIA Seed have no vehicleLocation
                if (newStatus.vehicleLocation.coord != undefined) {
                    const latitude = newStatus.vehicleLocation.coord.lat;
                    const longitude = newStatus.vehicleLocation.coord.lon;
                    await this.setStateAsync(vin + '.vehicleLocation.lat', { val: latitude, ack: true });
                    await this.setStateAsync(vin + '.vehicleLocation.lon', { val: longitude, ack: true });
                    await this.setStateAsync(vin + '.vehicleLocation.speed', { val: newStatus.vehicleLocation.speed.value, ack: true });
                }
            }
    
            //Odometer
            await this.setStateAsync(vin + '.odometer.value', { val: newStatus.odometer.value, ack: true });
            await this.setStateAsync(vin + '.odometer.unit', { val: newStatus.odometer.unit, ack: true });
    
            //open / door
            await this.setStateAsync(vin + '.vehicleStatus.doorLock', { val: newStatus.vehicleStatus.doorLock, ack: true });
            await this.setStateAsync(vin + '.vehicleStatus.trunkOpen', { val: newStatus.vehicleStatus.trunkOpen, ack: true });
            await this.setStateAsync(vin + '.vehicleStatus.hoodOpen', { val: newStatus.vehicleStatus.hoodOpen, ack: true });
    
            this.checkDoor(vin, newStatus.vehicleStatus.doorOpen);
    
            //status parameter
            await this.setStateAsync(vin + '.vehicleStatus.airCtrlOn', { val: newStatus.vehicleStatus.airCtrlOn, ack: true });
            await this.setStateAsync(vin + '.vehicleStatus.smartKeyBatteryWarning', { val: newStatus.vehicleStatus.smartKeyBatteryWarning, ack: true });
            await this.setStateAsync(vin + '.vehicleStatus.washerFluidStatus', { val: newStatus.vehicleStatus.washerFluidStatus, ack: true });
            await this.setStateAsync(vin + '.vehicleStatus.breakOilStatus', { val: newStatus.vehicleStatus.breakOilStatus, ack: true });
            await this.setStateAsync(vin + '.vehicleStatus.steerWheelHeat', { val: newStatus.vehicleStatus.steerWheelHeat, ack: true });
            await this.setStateAsync(vin + '.vehicleStatus.sideBackWindowHeat', { val: newStatus.vehicleStatus.sideBackWindowHeat, ack: true });
        }
    
        async checkDoor(vin, doors) {
            if (doors != undefined) {
                let frontLeft = doors.frontLeft;
                let frontRight = doors.frontRight;
                let backLeft = doors.backLeft;
                let backRight = doors.backRight;
    
            // HEV hyundai send 0 but we need boolean
                if (typeof frontLeft == 'number') {
                    frontLeft = frontLeft == 0 ? false : true;
                }
    
                if (typeof frontRight == 'number') {
                    frontRight = frontRight == 0 ? false : true;
                }
    
                if (typeof backLeft == 'number') {
                    backLeft = backLeft == 0 ? false : true;
                }
    
                if (typeof backRight == 'number') {
                    backRight = backRight == 0 ? false : true;
                }
    
                await this.setStateAsync(vin + '.vehicleStatus.doorOpen.frontLeft', { val: frontLeft, ack: true });
                await this.setStateAsync(vin + '.vehicleStatus.doorOpen.frontRight', { val: frontRight, ack: true });
                await this.setStateAsync(vin + '.vehicleStatus.doorOpen.backLeft', { val: backLeft, ack: true });
                await this.setStateAsync(vin + '.vehicleStatus.doorOpen.backRight', { val: backRight, ack: true });
            }
        }
    
        /**
         * Functions to create the ioBroker objects
         */
    
        async setControlObjects(vin) {
            await this.setObjectNotExistsAsync(vin + '.control.charge', {
                type: 'state',
                common: {
                    name: 'Start charging',
                    type: 'boolean',
                    role: 'button',
                    read: true,
                    write: true,
                },
                native: {},
            });
            this.subscribeStates(vin + '.control.charge');
    
            await this.setObjectNotExistsAsync(vin + '.control.charge_stop', {
                type: 'state',
                common: {
                    name: 'Stop charging',
                    type: 'boolean',
                    role: 'button',
                    read: true,
                    write: true,
                },
                native: {},
            });
            this.subscribeStates(vin + '.control.charge_stop');
    
            await this.setObjectNotExistsAsync(vin + '.control.lock', {
                type: 'state',
                common: {
                    name: 'Lock the vehicle',
                    type: 'boolean',
                    role: 'button',
                    read: true,
                    write: true,
                },
                native: {},
            });
            this.subscribeStates(vin + '.control.lock');
    
            await this.setObjectNotExistsAsync(vin + '.control.unlock', {
                type: 'state',
                common: {
                    name: 'Unlock the vehicle',
                    type: 'boolean',
                    role: 'button',
                    read: true,
                    write: true,
                },
                native: {},
            });
            this.subscribeStates(vin + '.control.unlock');
    
            await this.setObjectNotExistsAsync(vin + '.control.start', {
                type: 'state',
                common: {
                    name: 'Start clima for the vehicle',
                    type: 'boolean',
                    role: 'button',
                    read: true,
                    write: true,
                },
                native: {},
            });
            this.subscribeStates(vin + '.control.start');
            
            await this.setObjectNotExistsAsync(vin + '.control.set.airTemp', {
                type: 'state',
                common: {
                    name: 'set air temperature for clima',
                    type: 'number',
                    role: 'value.temperature',
                    read: true,
                    write: true,
                    def: 20,
                },
                native: {},
            });
            
            await this.setObjectNotExistsAsync(vin + '.control.set.defrost', {
                type: 'state',
                common: {
                    name: 'set defrost function for clima',
                    type: 'boolean',
                    role: 'state',
                    read: true,
                    write: true,
                    def: false,
                },
                native: {},
            });
    
            await this.setObjectNotExistsAsync(vin + '.control.set.heating', {
                type: 'state',
                common: {
                    name: 'set heating function for clima',
                    type: 'number',
                    role: 'state',
                    read: true,
                    write: true,
                    def: 0,
                },
                native: {},
            });
    
            await this.setObjectNotExistsAsync(vin + '.control.set.airCtrl', {
                type: 'state',
                common: {
                    name: 'set airCtrl function for clima',
                    type: 'boolean',
                    role: 'state',
                    read: true,
                    write: true,
                    def: false,
                },
                native: {},
            });
            
            await this.setObjectNotExistsAsync(vin + '.control.stop', {
                type: 'state',
                common: {
                    name: 'Stop clima for the vehicle',
                    type: 'boolean',
                    role: 'button',
                    read: true,
                    write: true,
                },
                native: {},
            });
            this.subscribeStates(vin + '.control.stop');
    
            await this.setObjectNotExistsAsync(vin + '.control.force_refresh', {
                type: 'state',
                common: {
                    name: 'Force refresh vehicle status',
                    type: 'boolean',
                    role: 'button',
                    read: true,
                    write: true,
                },
                native: {},
            });
            this.subscribeStates(vin + '.control.force_refresh');
            
            await this.setObjectNotExistsAsync(vin + '.control.force_update', {
                type: 'state',
                common: {
                    name: 'Force update state for force refresh',
                    type: 'boolean',
                    role: 'button',
                    read: true,
                    write: true,
                    def: true,
                },
                native: {},
            });         
            this.subscribeStates(vin + '.control.force_update');
       }
    
       async setStatusObjects(vin) {          
            await this.setObjectNotExistsAsync(`${vin}.lastInfoUpdate`, {
                type: 'state',
                common: {
                    name: 'Date/Time of last information update',
                    type: 'number',
                    role: 'value.time',
                    read: true,
                    write: false
                },
                native: {},
            });
         
            await this.setObjectNotExistsAsync(`${vin}.error_counter`, {
                type: 'state',
                common: {
                    name: 'error_counter',
                    type: 'number',
                    role: 'state',
                    read: true,
                    write: false,
                    def: 0,
                },
                native: {},
            });
            
            await this.setObjectNotExistsAsync(vin + '.vehicleStatusRaw', {
                type: 'channel',
                common: {
                    name: 'Unformatted vehicle status',               
                },
                native: {},
            });
            
            
            //Bereicht vehicleStatus
            await this.setObjectNotExistsAsync(vin + '.vehicleStatus.doorLock', {
                type: 'state',
                common: {
                    name: 'Vehicle doors locked',
                    type: 'boolean',
                    role: 'indicator',
                    read: true,
                    write: false,
                },
                native: {},
            });
    
            await this.setObjectNotExistsAsync(vin + '.vehicleStatus.trunkOpen', {
                type: 'state',
                common: {
                    name: 'Trunk open',
                    type: 'boolean',
                    role: 'indicator',
                    read: true,
                    write: false,
                },
                native: {},
            });
    
            await this.setObjectNotExistsAsync(vin + '.vehicleStatus.hoodOpen', {
                type: 'state',
                common: {
                    name: 'Hood open',
                    type: 'boolean',
                    role: 'indicator',
                    read: true,
                    write: false,
                },
                native: {},
            });
    
            //Doors open
            await this.setObjectNotExistsAsync(vin + '.vehicleStatus.doorOpen.frontLeft', {
                type: 'state',
                common: {
                    name: 'Door open front left open',
                    type: 'boolean',
                    role: 'indicator',
                    read: true,
                    write: false,
                },
                native: {},
            });
    
            await this.setObjectNotExistsAsync(vin + '.vehicleStatus.doorOpen.frontRight', {
                type: 'state',
                common: {
                    name: 'Door open front right open',
                    type: 'boolean',
                    role: 'indicator',
                    read: true,
                    write: false,
                },
                native: {},
            });
    
            await this.setObjectNotExistsAsync(vin + '.vehicleStatus.doorOpen.backLeft', {
                type: 'state',
                common: {
                    name: 'Door open back left open',
                    type: 'boolean',
                    role: 'indicator',
                    read: true,
                    write: false,
                },
                native: {},
            });
    
            await this.setObjectNotExistsAsync(vin + '.vehicleStatus.doorOpen.backRight', {
                type: 'state',
                common: {
                    name: 'Door open back right left open',
                    type: 'boolean',
                    role: 'indicator',
                    read: true,
                    write: false,
                },
                native: {},
            });
    
            await this.setObjectNotExistsAsync(vin + '.vehicleStatus.airCtrlOn', {
                type: 'state',
                common: {
                    name: 'Vehicle air control',
                    type: 'boolean',
                    role: 'indicator',
                    read: true,
                    write: false,
                },
                native: {},
            });
    
            await this.setObjectNotExistsAsync(vin + '.vehicleStatus.airTemp', {
                type: 'state',
                common: {
                    name: 'Vehicle air tempereature',
                    type: 'number',
                    role: 'indicator',
                    read: true,
                    write: false,
                },
                native: {},
            });
    
            await this.setObjectNotExistsAsync(vin + '.vehicleStatus.smartKeyBatteryWarning', {
                type: 'state',
                common: {
                    name: 'Smart key battery Warning',
                    type: 'boolean',
                    role: 'indicator',
                    read: true,
                    write: false,
                },
                native: {},
            });
    
            await this.setObjectNotExistsAsync(vin + '.vehicleStatus.washerFluidStatus', {
                type: 'state',
                common: {
                    name: 'Washer fluid status',
                    type: 'boolean',
                    role: 'indicator',
                    read: true,
                    write: false,
                },
                native: {},
            });
    
            await this.setObjectNotExistsAsync(vin + '.vehicleStatus.breakOilStatus', {
                type: 'state',
                common: {
                    name: 'Breal oil status',
                    type: 'boolean',
                    role: 'indicator',
                    read: true,
                    write: false,
                },
                native: {},
            });
    
            await this.setObjectNotExistsAsync(vin + '.vehicleStatus.steerWheelHeat', {
                type: 'state',
                common: {
                    name: 'Steer wheel heat',
                    type: 'boolean',
                    role: 'indicator',
                    read: true,
                    write: false,
                },
                native: {},
            });
    
            await this.setObjectNotExistsAsync(vin + '.vehicleStatus.sideBackWindowHeat', {
                type: 'state',
                common: {
                    name: 'Side back window heat',
                    type: 'number',
                    role: 'indicator',
                    read: true,
                    write: false,
                },
                native: {},
            });
    
            await this.setObjectNotExistsAsync(vin + '.vehicleStatus.dte', {
                type: 'state',
                common: {
                    name: 'Vehicle total available range',
                    type: 'number',
                    role: 'indicator',
                    read: true,
                    write: false,
                },
                native: {},
            });
    
            await this.setObjectNotExistsAsync(vin + '.vehicleStatus.evModeRange', {
                type: 'state',
                common: {
                    name: 'Vehicle total available range for ev',
                    type: 'number',
                    role: 'indicator',
                    read: true,
                    write: false,
                },
                native: {},
            });
    
            await this.setObjectNotExistsAsync(vin + '.vehicleStatus.gasModeRange', {
                type: 'state',
                common: {
                    name: 'Vehicle total available range for gas',
                    type: 'number',
                    role: 'indicator',
                    read: true,
                    write: false,
                },
                native: {},
            });
    
            //Charge
            await this.setObjectNotExistsAsync(vin + '.vehicleStatus.battery.charge_limit_slow', {
                type: 'state',
                common: {
                    name: 'Vehicle charge limit for slow charging',
                    type: 'number',
                    role: 'indicator',
                    read: true,
                    write: true,
                },
                native: {},
            });
            this.subscribeStates(vin + '.vehicleStatus.battery.charge_limit_slow');
    
            await this.setObjectNotExistsAsync(vin + '.vehicleStatus.battery.charge_limit_fast', {
                type: 'state',
                common: {
                    name: 'Vehicle charge limit for fast charging',
                    type: 'number',
                    role: 'indicator',
                    read: true,
                    write: true,
                },
                native: {},
            });
            this.subscribeStates(vin + '.vehicleStatus.battery.charge_limit_fast');
    
            await this.setObjectNotExistsAsync(vin + '.vehicleStatus.battery.minutes_to_charged', {
                type: 'state',
                common: {
                    name: 'Vehicle minutes to charged',
                    type: 'number',
                    role: 'indicator',
                    read: true,
                    write: true,
                },
                native: {},
            });
    
            //Battery
            await this.setObjectNotExistsAsync(vin + '.vehicleStatus.battery.soc', {
                type: 'state',
                common: {
                    name: 'Vehicle battery state of charge',
                    type: 'number',
                    role: 'indicator',
                    read: true,
                    write: false,
                },
                native: {},
            });
    
            await this.setObjectNotExistsAsync(vin + '.vehicleStatus.battery.charge', {
                type: 'state',
                common: {
                    name: 'Vehicle charging',
                    type: 'boolean',
                    role: 'indicator',
                    read: true,
                    write: false,
                },
                native: {},
            });
    
            await this.setObjectNotExistsAsync(vin + '.vehicleStatus.battery.plugin', {
                type: 'state',
                common: {
                    name: 'Charger connected (UNPLUGED = 0, FAST = 1, PORTABLE = 2, STATION = 3)',
                    type: 'number',
                    role: 'indicator',
                    read: true,
                    write: false,
                },
                native: {},
            });
    
            await this.setObjectNotExistsAsync(vin + '.vehicleStatus.battery.soc-12V', {
                type: 'state',
                common: {
                    name: 'Vehicle 12v battery state of charge',
                    type: 'number',
                    role: 'indicator',
                    read: true,
                    write: false,
                },
                native: {},
            });
    
            await this.setObjectNotExistsAsync(vin + '.vehicleStatus.battery.state-12V', {
                type: 'state',
                common: {
                    name: 'Vehicle 12v battery State',
                    type: 'number',
                    role: 'indicator',
                    read: true,
                    write: false,
                },
                native: {},
            });
    
            //Bereich vehicleLocation
            await this.setObjectNotExistsAsync(vin + '.vehicleLocation.lat', {
                type: 'state',
                common: {
                    name: 'Vehicle position latitude',
                    type: 'string',
                    role: 'indicator',
                    read: true,
                    write: false,
                },
                native: {},
            });
    
            await this.setObjectNotExistsAsync(vin + '.vehicleLocation.lon', {
                type: 'state',
                common: {
                    name: 'Vehicle position longitude',
                    type: 'string',
                    role: 'indicator',
                    read: true,
                    write: false,
                },
                native: {},
            });
    
            await this.setObjectNotExistsAsync(vin + '.vehicleLocation.speed', {
                type: 'state',
                common: {
                    name: 'Vehicle speed',
                    type: 'number',
                    role: 'indicator',
                    read: true,
                    write: false,
                },
                native: {},
            });
    
            //Bereich Odometer
            await this.setObjectNotExistsAsync(vin + '.odometer.value', {
                type: 'state',
                common: {
                    name: 'Odometer value',
                    type: 'number',
                    role: 'indicator',
                    read: true,
                    write: false,
                },
                native: {},
            });
    
            await this.setObjectNotExistsAsync(vin + '.odometer.unit', {
                type: 'state',
                common: {
                    name: 'Odometer unit',
                    type: 'number',
                    role: 'indicator',
                    read: true,
                    write: false,
                },
                native: {},
            });
        }
        async cleanObjects() {
            const controlState = await this.getObjectAsync('control.charge');
    
            if (controlState) {
                await this.delObjectAsync('control', { recursive: true });
                await this.delObjectAsync('odometer', { recursive: true });
                await this.delObjectAsync('vehicleLocation', { recursive: true });
                await this.delObjectAsync('vehicleStatus', { recursive: true });
            }
        }
    
        getCircularReplacer() {
            const seen = new WeakSet();
            return (key, value) => {
                if (typeof value === 'object' && value !== null) {
                    if (seen.has(value)) {
                        return;
                    }
                    seen.add(value);
                }
                return value;
            };
        }
    
        getCelsiusFromTempcode(tempCode) {
            // create a range
            const tempRange = [];
            //Range for EU
            for (let i = 14; i <= 30; i += 0.5) {
                tempRange.push(i);
            }
    
            // get the index
            const tempIndex = parseInt(tempCode, 16);
    
            // return the relevant celsius temp
            return tempRange[tempIndex];
        }
    }
    
    if (require.main !== module) {
        // Export the constructor in compact mode
        /**
         * @param {Partial<utils.AdapterOptions>} [options={}]
         */
        module.exports = (options) => new Bluelink(options);
    } else {
        // otherwise start the instance directly
        new Bluelink();
    }
    

    Diese Punkte haben sich zum original geändert:

    • es hatte sich ein kleiner Fehler eingeschlichen der den Wert des neuen States "force_update" das @arteck mit der Version 2.2.7 eingeführt hat nicht richtig an "Bluelinky" übergeben hat (hier fehlte ein .val)
    • sowohl die "Full Status" Abrage als auch die "Fallback" Abfrage kann nun mittels des neuen States "force_update" geschaltet werden, so dass man stets wählen kann ob die Daten nur vom Hyundai-Server kommen (false) oder direkt vom Auto (true) geholt werden.
    • Beim Start des Adapters wird die Einstellung des States "force_update" übergangen und die Daten auf jeden Fall vom PKW geholt, so dass die Daten auf jeden Fall top aktuell sind. Danach muss dann jeder über den State "force_update" entscheiden was er will.
    • Der Zeitstempel "lastInfoUpdate" wird nun erst nach einem erfolgreichen Update gesetzt, so dass man hieran sehen kann ob und wann das letzte erfolgreiche Update erfolgt ist.
    • @Michaelnorge den hard-gecodeten Wert für die Batterieüberwachung habe ich von 88 auf 60 geändert. Vielleicht könnte man das ja mal in die Adaptereinstellungen integrieren, so dass man diesen Wert individuell anpassen kann.

    (Ich hatte das hier schon mal geschrieben: Ich kann eigentlich kein Java programmieren. Ich kann zwar ein Script lesen und verstehe auch zum großen Teil was es macht das war's dann aber auch schon. D.h. die Änderungen in meiner "main.js" sind durch probieren, copy-paste und ein weinig nachlesen entstanden. Will heißen, das Script läuft zwar prima, ist aber nicht unbedingt programmiertechnisch perfekt.)

    Ich selbst nutze die Einstellung FALSE beim State "force_update" mit 360 Abfragen pro Tag (also alle 4 min. eine Abfrage). Mehr Abfragen (alle 3 min. oder mehr) führten bei mir zu einer Fehlermeldung des Hyundai-Servers, dass ich zu viele Abfragen pro Tag an den Server stellen würde. Dann ging sogar die App nicht mehr...
    Sobald ich irgendwie registriere, dass mein Auto geladen wird (Ioniq 5) z.B. Rückmeldung bei der Server Abfrage oder Meldung durch meine Wall-Box, schalte ich per Blockly Script den State "force_update" um auf true, so dass die Daten direkt vom PKW geholt werden. Nach Beendigung des Ladevorgangs schalte ich dann wieder zurück auf false. Das funktioniert super und belastet halt die 12V Batterie so gut wie gar nicht mehr.

    ? Offline
    ? Offline
    Ein ehemaliger Benutzer
    schrieb am zuletzt editiert von Ein ehemaliger Benutzer
    #958

    @stefan-cloer Hi Stefan,

    super, vielen Dank! Das kann ich hier sehr gut nachvollziehen, jetzt kommt kein Fehler mehr im Log.. lag also doch nicht am Hyundai-Server.. :)

    ps: kannst du das vielleicht als Pull-Request einstellen, damit @arteck den Adapter updaten kann und ein neues Release macht?

    S 1 Antwort Letzte Antwort
    0
    • ? Ein ehemaliger Benutzer

      @stefan-cloer Hi Stefan,

      super, vielen Dank! Das kann ich hier sehr gut nachvollziehen, jetzt kommt kein Fehler mehr im Log.. lag also doch nicht am Hyundai-Server.. :)

      ps: kannst du das vielleicht als Pull-Request einstellen, damit @arteck den Adapter updaten kann und ein neues Release macht?

      S Offline
      S Offline
      stefan.cloer
      schrieb am zuletzt editiert von
      #959

      @ilovegym Tcha, wenn ich wüsste wie ich das machen soll...

      ? 1 Antwort Letzte Antwort
      0
      • S stefan.cloer

        @ilovegym Tcha, wenn ich wüsste wie ich das machen soll...

        ? Offline
        ? Offline
        Ein ehemaliger Benutzer
        schrieb am zuletzt editiert von
        #960

        @stefan-cloer hast auch wieder Recht, da die komplette main.js ja schon da ist, muss @arteck sie nur ersetzen..

        Ich machs ja ohne Probleme in der Console, man muss halt aufpassen, dass man entweder mit iobroker angemeldet ist oder anschliessend ein

        sudo chown iobroker:iobroker main.js
        

        macht, damit die Rechte wieder stimmen...
        :)

        1 Antwort Letzte Antwort
        0
        • S stefan.cloer

          @arteck
          Ich habe dann Anfang der Woche auch mal den Wechsel von meiner selbst angepassten "main.js" des Adapters auf die Version 2.2.8 gemacht. Ich habe also die 2.2.7 übersprungen.
          Nach der Installation von 2.2.8 funktionierte die Abfrage des Autos leider bei mir auch nicht mehr so schön wie sie zuvor bei meiner selbst gemachten Anpassung lief. Ich hatte auch sehr schnell den Verdacht, dass sich in der 2.2.8 ein Fehler befindet oder zumindest etwas anders lief als bei meiner eigenen Version. Daraufhin habe ich mal die neue "main.js" durchgeackert und tatsächlich ein paar Dinge gefunden die meiner Meinung nach nicht korrekt sind bzw. aus meiner Sicht besser gelöst werden könnten. (Das soll keine Kritik an der tollen Arbeit von @arteck und @Newan sein, ich hatte einfach nur gemerkt, dass sich da was anders verhält als zuvor.)
          Ich habe daraufhin noch mal ein paar Anpassungen an der "main.js" der Version 2.2.8 vorgenommen. Jetzt läuft sie wieder zu meiner vollsten Zufriedenheit. Gerne kann ich das mit euch teilen:

          'use strict';
          
          const utils = require('@iobroker/adapter-core');
          const bluelinky = require('bluelinky');
          const Json2iob = require('./lib/json2iob');
          let force_update = {};   
          force_update.val = true;   
          
          const adapterIntervals = {}; //halten von allen Intervallen
          let request_count = 48; // halbstündig sollte als Standardeinstellung reichen (zu häufige Abfragen entleeren die Batterie spürbar)
          let client;
          
          let slow_charging;
          let fast_charging;
          
          const POSSIBLE_CHARGE_LIMIT_VALUES = [50, 60, 70, 80, 90, 100];
          
          class Bluelink extends utils.Adapter {
              /**
               * @param {Partial<utils.AdapterOptions>} [options={}]
               */
              constructor(options) {
                  super({
                      ...options,
                      name: 'bluelink',
                  });
          
                  this.on('ready', this.onReady.bind(this));
                  this.on('stateChange', this.onStateChange.bind(this));
                  // this.on('objectChange', this.onObjectChange.bind(this));
                  // this.on('message', this.onMessage.bind(this));
                  this.on('unload', this.onUnload.bind(this));
                  this.vehiclesDict = {};
                  this.batteryState12V = {};
                  this.vehicles = [];
                  this.json2iob = new Json2iob(this);
                  adapterIntervals.evHistoryInterval = null;
                  this.countError = 0;
              }
          
              //Start Adapter
              async onReady() {
                  //first check account settings
                  if (this.config.request < 1) {
                      this.log.warn('Request is under 1 -> got to default 100');
                  } else {
                      request_count = this.config.request;
                  }
          
                  if (this.config.username == '') {
                      this.log.error('No Username set');
                  } else {
                      //Start logic with login
                      this.login();
                  }
              }
          
              /**
               * Is called when adapter shuts down - callback has to be called under any circumstances!
               * @param {() => void} callback
               */
              onUnload(callback) {
                  try {
                      clearTimeout(adapterIntervals.readAllStates);
                      clearInterval(adapterIntervals.evHistoryInterval);
                      this.log.info('Adapter bluelink cleaned up everything...');
                      callback();
                  } catch (e) {
                      callback();
                  }
              }
          
              async onStateChange(id, state) {
                  if (state) {
                      if (id.indexOf('.control.') === -1) {
                          return;
                      }
                      this.log.debug('New Event for state: ' + JSON.stringify(state));
                      this.log.debug('ID: ' + JSON.stringify(id));
          
                      const vin = id.split('.')[2];
                      const vehicle = this.vehiclesDict[vin];
                      const tmpControl = id.split('.')[4];
                      let response;
                      switch (tmpControl) {
                          case 'lock':
                              this.log.info('Starting lock for vehicle');
                              response = await vehicle.lock();
                              this.log.info(response);
                              break;
                          case 'unlock':
                              this.log.info('Starting unlock for vehicle');
                              response = await vehicle.unlock();
                              this.log.info(response);
                              break;
                          case 'start':
                              this.log.info('Starting clima for vehicle');
          
                              let airCtrl = await this.getStateAsync(`${vin}.control.set.airCtrl`);                
                              let airTempC = await this.getStateAsync(`${vin}.control.set.airTemp`);
                              let airTempF = (airTempC.val * 9/5) + 32;
                              let defrost = await this.getStateAsync(`${vin}.control.set.defrost`);
                              let heating = await this.getStateAsync(`${vin}.control.set.heating`);
                            
                              try {
                                  response = await vehicle.start({
                                      airCtrl: airCtrl.val,
                                      igniOnDuration: 10,
                                      airTempvalue: airTempF,
                                      defrost: defrost.val,
                                      heating1: heating.val,
                                  });
                              } catch (err) {
                                  this.log.error(JSON.stringify(err));                    
                              }    
                              break;
                          case 'stop':
                              this.log.info('Stop clima for vehicle');
                              response = await vehicle.stop();
                              this.log.debug(JSON.stringify(response));
                              break;
                          case 'force_refresh':
                              this.log.info('Forcing refresh');
                              //Force refresh for new states
                              this.readStatus(true);
                              break;
                          case 'force_update':
          			        force_update = await this.getStateAsync(`${vin}.control.force_update`);   
          	            	if(force_update.val) {
              	                this.log.info('Update method for ' + vin + ' changed to "directly from the car"');
                  	        } else {
                      	        this.log.info('Update method for ' + vin + ' changed to "from the server"');
                          	}
                              break;
                          case 'charge':
                              this.log.info('Start charging');
                              response = await vehicle.startCharge();
                              break;
                          case 'charge_stop':
                              this.log.info('Stop charging');
                              response = await vehicle.stopCharge();
                              break;
                          case 'battery':
                              if (!state.ack) {
                                  if (!POSSIBLE_CHARGE_LIMIT_VALUES.includes(state.val)) {
                                      this.log.error(`Charge target values are limited to ${POSSIBLE_CHARGE_LIMIT_VALUES.join(', ')}`);
                                  } else {
                                      this.log.info('Set new charging options');
                                      const charge_option = { fast: fast_charging, slow: slow_charging };
                                      if (tmpControl[4] == 'charge_limit_fast') {
                                          //set fast charging
                                          this.log.debug('Set fast charging');
                                          charge_option.fast = state.val;
                                      } else {
                                          //set slow charging
                                          this.log.debug('Set slow charging');
                                          charge_option.slow = state.val;
                                      }
                                      response = await vehicle.setChargeTargets(charge_option);
                                      this.log.debug(JSON.stringify(response));
                                  }
                              }
                              break;
                          default:
                              this.log.error('No command for Control found for: ' + id);
                      }
                  }
              }
          
              /**
               * Funktion to login in bluelink / UVO
               */
              login() {
                  try {
                      this.log.info('Login to api');
                      const tmpConfig = {
                          username: this.config.username,
                          password: this.config.client_secret,
                          pin: this.config.client_secret_pin,
                          brand: this.config.brand,
                          region: 'EU', //set over GUI next time
                          language:  this.config.language,
                      };
          
                      // @ts-ignore
                      client = new bluelinky(tmpConfig);
          
                      client.on('ready', async (vehicles) => {
                          // wir haben eine Verbindung und haben Autos
                          this.log.info(vehicles.length + ' Vehicles found');
                          this.log.debug(JSON.stringify(vehicles, this.getCircularReplacer()));
          
                          this.vehicles = vehicles;
                          for (const vehicle of vehicles) {
                              const vin = vehicle.vehicleConfig.vin;
                              this.vehiclesDict[vin] = vehicle;
                              await this.setObjectNotExistsAsync(vin, {
                                  type: 'device',
                                  common: {
                                      name: vehicle.vehicleConfig.nickname,
                                  },
                                  native: {},
                              });
          
                              await this.setControlObjects(vin);
                              await this.setStatusObjects(vin);
          
                              await this.setObjectNotExistsAsync(vin + '.general', {
                                  type: 'channel',
                                  common: {
                                      name: 'General Information',
                                  },
                                  native: {},
                              });
                              await this.json2iob.parse(vin + '.general', vehicle.vehicleConfig);
                              if (this.config.evHistory) {
                                  await this.receiveEVInformation(vehicle, vin);
                                  adapterIntervals.evHistoryInterval = setInterval(() => {
                                      this.receiveEVInformation(vehicle, vin);
                                  }, 24 * 60 * 60 * 1000); //24h
                              }
                          }
                          //start time cycle
                          await this.readStatus();
          
                          //clean legacy states
                          this.cleanObjects();
                      });
          
                      client.on('error', async (err) => {
                          // something went wrong with login
                          this.log.debug('Error on Api login');
                          this.log.error(err);
                          this.log.error('Please logout in the app and relogin in the app');
                      });
                  } catch (error) {
                      this.log.error('Error in login/on function');
                      if (typeof error === 'string') {
                          this.log.error(error);
                      } else if (error instanceof Error) {
                          this.log.error(error.message);
                      }
                  }
              }
          
              //read new sates from vehicle
              async readStatus(force = false) {
                  //read new verhicle status
                  for (const vehicle of this.vehicles) {
                      const vin = vehicle.vehicleConfig.vin;
          
                      this.log.debug('Read new status from api for ' + vin);
                      if (this.batteryState12V[vin] && this.batteryState12V[vin] < 60) {
                          this.log.warn('12V Battery state is low: ' + this.batteryState12V[vin] + '%. Recharge to prevent damage!');
                          if (this.config.protectAgainstDeepDischarge && !force) {
                              this.log.warn('Auto Refresh is disabled, only use force refresh to reenable refresh if you are willing to risk your battery');
                              continue;
                          }
                      }
                      try {
                          let newStatus;
          
                      	if(force_update.val) {
                              this.log.info('Read new update for ' + vin + ' directly from the car');
                          } else {
                              this.log.info('Read new update for ' + vin + ' from the server');
                          }
                          	
                      	try {
                              newStatus = await vehicle.fullStatus({
                                  refresh: force_update.val,
                                  parsed: true,
                              });
                              //set all values
                              this.log.debug('Set new full status for ' + vin);
                              this.log.debug('RAW ' + JSON.stringify(newStatus));
                              
                              // raw data
                              await this.json2iob.parse(vin + '.vehicleStatusRaw', newStatus);
                              
                              await this.setNewFullStatus(newStatus, vin);
                              if (newStatus.vehicleStatus && newStatus.vehicleStatus.battery && newStatus.vehicleStatus.battery.batSoc) {
                                  this.log.debug('Set ' + newStatus.vehicleStatus.battery.batSoc + ' battery state for ' + vin);
                                  this.batteryState12V[vin] = newStatus.vehicleStatus.battery.batSoc;
                              }
          
                          } catch (error) {
                              if (typeof error === 'string') {
                                  this.log.error('Error on API-Request GetFullStatus');
                                  this.log.error(error);
                                  //TODO option abfragen
                              } else {
                                  //if(error.source.statusCode == 503) {
                                  this.log.info('Error on API-Full-Status - Fallback GetNormalStatus');
          
                                  //Abfrage Full hat nicht gekalppt. Haben wir einen Fallback?
                                  newStatus = await vehicle.status({
                                      refresh: force_update.val,
                                      parsed: true,
                                  });
                              	this.log.debug('Set new GetNormalStatus for ' + vin);
                                  this.log.debug(JSON.stringify(newStatus));
          
                                  await this.setNewStatus(newStatus, vin);
                                  if (newStatus.engine && newStatus.engine.batteryCharge12v) {
                                      this.log.debug('Set ' + newStatus.engine.batteryCharge12v + ' battery state for ' + vin);
                                      this.batteryState12V[vin] = newStatus.engine.batteryCharge12v;
                                  }
                              }
                          }
          
                          //Abfrage war erfolgreich, lösche ErrorCounter
                          this.countError = 0;
          
          		        force_update = await this.getStateAsync(`${vin}.control.force_update`);
                          this.log.info('Update for ' + vin + ' successfull');
          	  	       // last update
              	        await this.setStateAsync(`${vin}.lastInfoUpdate`, Number(Date.now()), true);
                      
                      } catch (error) {
                          this.countError += 1;  // add 1
                         
                          this.log.error('Error on API-Request Status, ErrorCount:' + this.countError);
                          if (typeof error === 'string') {
                              this.log.error(error);
                          } else if (error instanceof Error) {
                              this.log.error(error.message);
                          }
                      }
          
                      await this.setStateAsync(`${vin}.error_counter`, this.countError, true);
                      
                      if (this.countError > this.config.errorCounter) {
                          //Error counter over x erros, restart Adapter to fix te API Token
                          this.restart();
                      }
                  }
              
                  //set ne cycle
                  if (force) {
                      clearTimeout(adapterIntervals.readAllStates);
                  }
                  adapterIntervals.readAllStates = setTimeout(this.readStatus.bind(this), ((24 * 60) / request_count) * 60000);
              }
          
              async receiveEVInformation(vehicle, vin) {
                  try {
                      const driveHistory = await vehicle.driveHistory();
                      this.log.debug('driveHistory-Data: ' + JSON.stringify(driveHistory));
                      
                      if (driveHistory != undefined) { 
                      
                          await this.setObjectNotExistsAsync(vin + '.driveHistory', {
                              type: 'channel',
                              common: {
                                  name: 'drive history',
                              },
                              native: {},
                          });
                          await this.json2iob.parse(vin + '.driveHistory', driveHistory, { preferedArrayName: 'rawDate' });
                          const monthlyReport = await vehicle.monthlyReport();
                          await this.setObjectNotExistsAsync(vin + '.monthlyReport', {
                              type: 'channel',
                              common: {
                                  name: 'monthly report',
                              },
                              native: {},
                          });
                          await this.json2iob.parse(vin + '.monthlyReport', monthlyReport);
                          const tripInfo = await vehicle.tripInfo({ year: new Date().getFullYear(), month: new Date().getMonth() + 1 });
                          await this.setObjectNotExistsAsync(vin + '.tripInfo', {
                              type: 'channel',
                              common: {
                                  name: 'trip information',
                              },
                              native: {},
                          });
                          await this.json2iob.parse(vin + '.tripInfo', tripInfo);
                      }
                  } catch (error) {
                      this.log.error('EV History fetching failed');
                      if (typeof error === 'string') {
                          this.log.error(error);
                      } else if (error instanceof Error) {
                          this.log.error(error.message);
                      }
                  }
              }
          
              //Set new values to ioBroker for normal Status
              async setNewStatus(newStatus, vin) {
                  //chassis
                  await this.setStateAsync(vin + '.vehicleStatus.doorLock', { val: newStatus.chassis.locked, ack: true });
                  await this.setStateAsync(vin + '.vehicleStatus.trunkOpen', { val: newStatus.chassis.trunkOpen, ack: true });
                  await this.setStateAsync(vin + '.vehicleStatus.hoodOpen', { val: newStatus.chassis.hoodOpen, ack: true });
          
                  //chassis/doors
                  this.checkDoor(vin, newStatus.chassis.openDoors);
          
                  //chassis/tirePressure
               //   if (newStatus.chassis.tirePressureWarningLamp != undefined) {
               //
               //   }
          
                  //climate
                  await this.setStateAsync(vin + '.vehicleStatus.airCtrlOn', { val: newStatus.climate.active, ack: true });
                  await this.setStateAsync(vin + '.vehicleStatus.airTemp', { val: newStatus.climate.temperatureSetpoint, ack: true });
                  await this.setStateAsync(vin + '.vehicleStatus.steerWheelHeat', { val: newStatus.climate.steeringwheelHeat, ack: true });
                  //await this.setStateAsync(vin + '.vehicleStatus.sideBackWindowHeat', { val: newStatus.climate.sideBackWindowHeat, ack: true });
          
                  //Engine
                  await this.setStateAsync(vin + '.vehicleStatus.battery.soc', { val: newStatus.engine.batteryChargeHV, ack: true });
                  await this.setStateAsync(vin + '.vehicleStatus.battery.charge', { val: newStatus.engine.charging, ack: true });       
                  await this.setStateAsync(vin + '.vehicleStatus.battery.soc-12V', { val: newStatus.engine.batteryCharge12v, ack: true });
              }
          
              //Set new values to ioBroker
              async setNewFullStatus(newStatus, vin) {
                  await this.setStateAsync(vin + '.vehicleStatus.airCtrlOn', { val: newStatus.vehicleStatus.airCtrlOn, ack: true });
                  await this.setStateAsync(vin + '.vehicleStatus.airTemp', {
                      val: this.getCelsiusFromTempcode(newStatus.vehicleStatus.airTemp.value),
                      ack: true,
                  });
          
                  //Charge
          
                  //Bei Kia sind die Werte in einer targetSOClist
                  if (newStatus.vehicleStatus.evStatus != undefined) {
                      if (newStatus.vehicleStatus.evStatus.reservChargeInfos.targetSOClist != undefined) {
                          if (newStatus.vehicleStatus.evStatus.reservChargeInfos.targetSOClist[0].plugType == 1) {
                              //Slow  = 1  -> Index 0 ist slow
                              await this.setStateAsync(vin + '.vehicleStatus.battery.charge_limit_slow', {
                                  val: newStatus.vehicleStatus.evStatus.reservChargeInfos.targetSOClist[0].targetSOClevel,
                                  ack: true,
                              });
                              slow_charging = newStatus.vehicleStatus.evStatus.reservChargeInfos.targetSOClist[0].targetSOClevel;
                              await this.setStateAsync(vin + '.vehicleStatus.battery.charge_limit_fast', {
                                  val: newStatus.vehicleStatus.evStatus.reservChargeInfos.targetSOClist[1].targetSOClevel,
                                  ack: true,
                              });
                              fast_charging = newStatus.vehicleStatus.evStatus.reservChargeInfos.targetSOClist[1].targetSOClevel;
                          } else {
                              //fast  = 0  -> Index 0 ist fast
                              await this.setStateAsync(vin + '.vehicleStatus.battery.charge_limit_slow', {
                                  val: newStatus.vehicleStatus.evStatus.reservChargeInfos.targetSOClist[1].targetSOClevel,
                                  ack: true,
                              });
                              slow_charging = newStatus.vehicleStatus.evStatus.reservChargeInfos.targetSOClist[1].targetSOClevel;
                              await this.setStateAsync(vin + '.vehicleStatus.battery.charge_limit_fast', {
                                  val: newStatus.vehicleStatus.evStatus.reservChargeInfos.targetSOClist[0].targetSOClevel,
                                  ack: true,
                              });
                              fast_charging = newStatus.vehicleStatus.evStatus.reservChargeInfos.targetSOClist[0].targetSOClevel;
                          }
                      } else {
                          //Bei Hyundai sieht es anders aus:
                      }
          
                      //Nur für Elektro Fahrzeuge - Battery
                      await this.setStateAsync(vin + '.vehicleStatus.dte', {
                          val: newStatus.vehicleStatus.evStatus.drvDistance[0].rangeByFuel.totalAvailableRange.value,
                          ack: true,
                      });
                      await this.setStateAsync(vin + '.vehicleStatus.evModeRange', {
                          val: newStatus.vehicleStatus.evStatus.drvDistance[0].rangeByFuel.evModeRange.value,
                          ack: true,
                      });
                      if (newStatus.vehicleStatus.evStatus.drvDistance[0].rangeByFuel.gasModeRange != undefined) {
                          //Only for PHEV
                          await this.setStateAsync(vin + '.vehicleStatus.gasModeRange', {
                              val: newStatus.vehicleStatus.evStatus.drvDistance[0].rangeByFuel.gasModeRange.value,
                              ack: true,
                          });
                      }
          
                      await this.setStateAsync(vin + '.vehicleStatus.battery.soc', { val: newStatus.vehicleStatus.evStatus.batteryStatus, ack: true });
                      await this.setStateAsync(vin + '.vehicleStatus.battery.charge', { val: newStatus.vehicleStatus.evStatus.batteryCharge, ack: true });
                      await this.setStateAsync(vin + '.vehicleStatus.battery.plugin', { val: newStatus.vehicleStatus.evStatus.batteryPlugin, ack: true });
          
                      //Ladezeit anzeigen, da noch nicht klar welche Werte
                      await this.setStateAsync(vin + '.vehicleStatus.battery.minutes_to_charged', {
                          val: newStatus.vehicleStatus.evStatus.remainTime2.atc.value,
                          ack: true,
                      });
                      this.log.debug('Folgende Ladezeiten Moeglichkeiten wurden gefunden:');
                      this.log.debug(JSON.stringify(newStatus.vehicleStatus.evStatus.remainTime2));
                  } else {
                      //Kein Elektromodell, Diesel etc
                      await this.setStateAsync(vin + '.vehicleStatus.dte', { val: newStatus.vehicleStatus.dte.value, ack: true });
                  }
          
                  // nur für Kia              
                  if (newStatus.vehicleStatus.battery != undefined) {
                      await this.setStateAsync(vin + '.vehicleStatus.battery.soc-12V', { val: newStatus.vehicleStatus.battery.batSoc, ack: true });
                      await this.setStateAsync(vin + '.vehicleStatus.battery.state-12V', { val: newStatus.vehicleStatus.battery.batState, ack: true });
                  }
          
                  //Location
                  if (newStatus.vehicleLocation != undefined) {
                      //#47 KIA Seed have no vehicleLocation
                      if (newStatus.vehicleLocation.coord != undefined) {
                          const latitude = newStatus.vehicleLocation.coord.lat;
                          const longitude = newStatus.vehicleLocation.coord.lon;
                          await this.setStateAsync(vin + '.vehicleLocation.lat', { val: latitude, ack: true });
                          await this.setStateAsync(vin + '.vehicleLocation.lon', { val: longitude, ack: true });
                          await this.setStateAsync(vin + '.vehicleLocation.speed', { val: newStatus.vehicleLocation.speed.value, ack: true });
                      }
                  }
          
                  //Odometer
                  await this.setStateAsync(vin + '.odometer.value', { val: newStatus.odometer.value, ack: true });
                  await this.setStateAsync(vin + '.odometer.unit', { val: newStatus.odometer.unit, ack: true });
          
                  //open / door
                  await this.setStateAsync(vin + '.vehicleStatus.doorLock', { val: newStatus.vehicleStatus.doorLock, ack: true });
                  await this.setStateAsync(vin + '.vehicleStatus.trunkOpen', { val: newStatus.vehicleStatus.trunkOpen, ack: true });
                  await this.setStateAsync(vin + '.vehicleStatus.hoodOpen', { val: newStatus.vehicleStatus.hoodOpen, ack: true });
          
                  this.checkDoor(vin, newStatus.vehicleStatus.doorOpen);
          
                  //status parameter
                  await this.setStateAsync(vin + '.vehicleStatus.airCtrlOn', { val: newStatus.vehicleStatus.airCtrlOn, ack: true });
                  await this.setStateAsync(vin + '.vehicleStatus.smartKeyBatteryWarning', { val: newStatus.vehicleStatus.smartKeyBatteryWarning, ack: true });
                  await this.setStateAsync(vin + '.vehicleStatus.washerFluidStatus', { val: newStatus.vehicleStatus.washerFluidStatus, ack: true });
                  await this.setStateAsync(vin + '.vehicleStatus.breakOilStatus', { val: newStatus.vehicleStatus.breakOilStatus, ack: true });
                  await this.setStateAsync(vin + '.vehicleStatus.steerWheelHeat', { val: newStatus.vehicleStatus.steerWheelHeat, ack: true });
                  await this.setStateAsync(vin + '.vehicleStatus.sideBackWindowHeat', { val: newStatus.vehicleStatus.sideBackWindowHeat, ack: true });
              }
          
              async checkDoor(vin, doors) {
                  if (doors != undefined) {
                      let frontLeft = doors.frontLeft;
                      let frontRight = doors.frontRight;
                      let backLeft = doors.backLeft;
                      let backRight = doors.backRight;
          
                  // HEV hyundai send 0 but we need boolean
                      if (typeof frontLeft == 'number') {
                          frontLeft = frontLeft == 0 ? false : true;
                      }
          
                      if (typeof frontRight == 'number') {
                          frontRight = frontRight == 0 ? false : true;
                      }
          
                      if (typeof backLeft == 'number') {
                          backLeft = backLeft == 0 ? false : true;
                      }
          
                      if (typeof backRight == 'number') {
                          backRight = backRight == 0 ? false : true;
                      }
          
                      await this.setStateAsync(vin + '.vehicleStatus.doorOpen.frontLeft', { val: frontLeft, ack: true });
                      await this.setStateAsync(vin + '.vehicleStatus.doorOpen.frontRight', { val: frontRight, ack: true });
                      await this.setStateAsync(vin + '.vehicleStatus.doorOpen.backLeft', { val: backLeft, ack: true });
                      await this.setStateAsync(vin + '.vehicleStatus.doorOpen.backRight', { val: backRight, ack: true });
                  }
              }
          
              /**
               * Functions to create the ioBroker objects
               */
          
              async setControlObjects(vin) {
                  await this.setObjectNotExistsAsync(vin + '.control.charge', {
                      type: 'state',
                      common: {
                          name: 'Start charging',
                          type: 'boolean',
                          role: 'button',
                          read: true,
                          write: true,
                      },
                      native: {},
                  });
                  this.subscribeStates(vin + '.control.charge');
          
                  await this.setObjectNotExistsAsync(vin + '.control.charge_stop', {
                      type: 'state',
                      common: {
                          name: 'Stop charging',
                          type: 'boolean',
                          role: 'button',
                          read: true,
                          write: true,
                      },
                      native: {},
                  });
                  this.subscribeStates(vin + '.control.charge_stop');
          
                  await this.setObjectNotExistsAsync(vin + '.control.lock', {
                      type: 'state',
                      common: {
                          name: 'Lock the vehicle',
                          type: 'boolean',
                          role: 'button',
                          read: true,
                          write: true,
                      },
                      native: {},
                  });
                  this.subscribeStates(vin + '.control.lock');
          
                  await this.setObjectNotExistsAsync(vin + '.control.unlock', {
                      type: 'state',
                      common: {
                          name: 'Unlock the vehicle',
                          type: 'boolean',
                          role: 'button',
                          read: true,
                          write: true,
                      },
                      native: {},
                  });
                  this.subscribeStates(vin + '.control.unlock');
          
                  await this.setObjectNotExistsAsync(vin + '.control.start', {
                      type: 'state',
                      common: {
                          name: 'Start clima for the vehicle',
                          type: 'boolean',
                          role: 'button',
                          read: true,
                          write: true,
                      },
                      native: {},
                  });
                  this.subscribeStates(vin + '.control.start');
                  
                  await this.setObjectNotExistsAsync(vin + '.control.set.airTemp', {
                      type: 'state',
                      common: {
                          name: 'set air temperature for clima',
                          type: 'number',
                          role: 'value.temperature',
                          read: true,
                          write: true,
                          def: 20,
                      },
                      native: {},
                  });
                  
                  await this.setObjectNotExistsAsync(vin + '.control.set.defrost', {
                      type: 'state',
                      common: {
                          name: 'set defrost function for clima',
                          type: 'boolean',
                          role: 'state',
                          read: true,
                          write: true,
                          def: false,
                      },
                      native: {},
                  });
          
                  await this.setObjectNotExistsAsync(vin + '.control.set.heating', {
                      type: 'state',
                      common: {
                          name: 'set heating function for clima',
                          type: 'number',
                          role: 'state',
                          read: true,
                          write: true,
                          def: 0,
                      },
                      native: {},
                  });
          
                  await this.setObjectNotExistsAsync(vin + '.control.set.airCtrl', {
                      type: 'state',
                      common: {
                          name: 'set airCtrl function for clima',
                          type: 'boolean',
                          role: 'state',
                          read: true,
                          write: true,
                          def: false,
                      },
                      native: {},
                  });
                  
                  await this.setObjectNotExistsAsync(vin + '.control.stop', {
                      type: 'state',
                      common: {
                          name: 'Stop clima for the vehicle',
                          type: 'boolean',
                          role: 'button',
                          read: true,
                          write: true,
                      },
                      native: {},
                  });
                  this.subscribeStates(vin + '.control.stop');
          
                  await this.setObjectNotExistsAsync(vin + '.control.force_refresh', {
                      type: 'state',
                      common: {
                          name: 'Force refresh vehicle status',
                          type: 'boolean',
                          role: 'button',
                          read: true,
                          write: true,
                      },
                      native: {},
                  });
                  this.subscribeStates(vin + '.control.force_refresh');
                  
                  await this.setObjectNotExistsAsync(vin + '.control.force_update', {
                      type: 'state',
                      common: {
                          name: 'Force update state for force refresh',
                          type: 'boolean',
                          role: 'button',
                          read: true,
                          write: true,
                          def: true,
                      },
                      native: {},
                  });         
                  this.subscribeStates(vin + '.control.force_update');
             }
          
             async setStatusObjects(vin) {          
                  await this.setObjectNotExistsAsync(`${vin}.lastInfoUpdate`, {
                      type: 'state',
                      common: {
                          name: 'Date/Time of last information update',
                          type: 'number',
                          role: 'value.time',
                          read: true,
                          write: false
                      },
                      native: {},
                  });
               
                  await this.setObjectNotExistsAsync(`${vin}.error_counter`, {
                      type: 'state',
                      common: {
                          name: 'error_counter',
                          type: 'number',
                          role: 'state',
                          read: true,
                          write: false,
                          def: 0,
                      },
                      native: {},
                  });
                  
                  await this.setObjectNotExistsAsync(vin + '.vehicleStatusRaw', {
                      type: 'channel',
                      common: {
                          name: 'Unformatted vehicle status',               
                      },
                      native: {},
                  });
                  
                  
                  //Bereicht vehicleStatus
                  await this.setObjectNotExistsAsync(vin + '.vehicleStatus.doorLock', {
                      type: 'state',
                      common: {
                          name: 'Vehicle doors locked',
                          type: 'boolean',
                          role: 'indicator',
                          read: true,
                          write: false,
                      },
                      native: {},
                  });
          
                  await this.setObjectNotExistsAsync(vin + '.vehicleStatus.trunkOpen', {
                      type: 'state',
                      common: {
                          name: 'Trunk open',
                          type: 'boolean',
                          role: 'indicator',
                          read: true,
                          write: false,
                      },
                      native: {},
                  });
          
                  await this.setObjectNotExistsAsync(vin + '.vehicleStatus.hoodOpen', {
                      type: 'state',
                      common: {
                          name: 'Hood open',
                          type: 'boolean',
                          role: 'indicator',
                          read: true,
                          write: false,
                      },
                      native: {},
                  });
          
                  //Doors open
                  await this.setObjectNotExistsAsync(vin + '.vehicleStatus.doorOpen.frontLeft', {
                      type: 'state',
                      common: {
                          name: 'Door open front left open',
                          type: 'boolean',
                          role: 'indicator',
                          read: true,
                          write: false,
                      },
                      native: {},
                  });
          
                  await this.setObjectNotExistsAsync(vin + '.vehicleStatus.doorOpen.frontRight', {
                      type: 'state',
                      common: {
                          name: 'Door open front right open',
                          type: 'boolean',
                          role: 'indicator',
                          read: true,
                          write: false,
                      },
                      native: {},
                  });
          
                  await this.setObjectNotExistsAsync(vin + '.vehicleStatus.doorOpen.backLeft', {
                      type: 'state',
                      common: {
                          name: 'Door open back left open',
                          type: 'boolean',
                          role: 'indicator',
                          read: true,
                          write: false,
                      },
                      native: {},
                  });
          
                  await this.setObjectNotExistsAsync(vin + '.vehicleStatus.doorOpen.backRight', {
                      type: 'state',
                      common: {
                          name: 'Door open back right left open',
                          type: 'boolean',
                          role: 'indicator',
                          read: true,
                          write: false,
                      },
                      native: {},
                  });
          
                  await this.setObjectNotExistsAsync(vin + '.vehicleStatus.airCtrlOn', {
                      type: 'state',
                      common: {
                          name: 'Vehicle air control',
                          type: 'boolean',
                          role: 'indicator',
                          read: true,
                          write: false,
                      },
                      native: {},
                  });
          
                  await this.setObjectNotExistsAsync(vin + '.vehicleStatus.airTemp', {
                      type: 'state',
                      common: {
                          name: 'Vehicle air tempereature',
                          type: 'number',
                          role: 'indicator',
                          read: true,
                          write: false,
                      },
                      native: {},
                  });
          
                  await this.setObjectNotExistsAsync(vin + '.vehicleStatus.smartKeyBatteryWarning', {
                      type: 'state',
                      common: {
                          name: 'Smart key battery Warning',
                          type: 'boolean',
                          role: 'indicator',
                          read: true,
                          write: false,
                      },
                      native: {},
                  });
          
                  await this.setObjectNotExistsAsync(vin + '.vehicleStatus.washerFluidStatus', {
                      type: 'state',
                      common: {
                          name: 'Washer fluid status',
                          type: 'boolean',
                          role: 'indicator',
                          read: true,
                          write: false,
                      },
                      native: {},
                  });
          
                  await this.setObjectNotExistsAsync(vin + '.vehicleStatus.breakOilStatus', {
                      type: 'state',
                      common: {
                          name: 'Breal oil status',
                          type: 'boolean',
                          role: 'indicator',
                          read: true,
                          write: false,
                      },
                      native: {},
                  });
          
                  await this.setObjectNotExistsAsync(vin + '.vehicleStatus.steerWheelHeat', {
                      type: 'state',
                      common: {
                          name: 'Steer wheel heat',
                          type: 'boolean',
                          role: 'indicator',
                          read: true,
                          write: false,
                      },
                      native: {},
                  });
          
                  await this.setObjectNotExistsAsync(vin + '.vehicleStatus.sideBackWindowHeat', {
                      type: 'state',
                      common: {
                          name: 'Side back window heat',
                          type: 'number',
                          role: 'indicator',
                          read: true,
                          write: false,
                      },
                      native: {},
                  });
          
                  await this.setObjectNotExistsAsync(vin + '.vehicleStatus.dte', {
                      type: 'state',
                      common: {
                          name: 'Vehicle total available range',
                          type: 'number',
                          role: 'indicator',
                          read: true,
                          write: false,
                      },
                      native: {},
                  });
          
                  await this.setObjectNotExistsAsync(vin + '.vehicleStatus.evModeRange', {
                      type: 'state',
                      common: {
                          name: 'Vehicle total available range for ev',
                          type: 'number',
                          role: 'indicator',
                          read: true,
                          write: false,
                      },
                      native: {},
                  });
          
                  await this.setObjectNotExistsAsync(vin + '.vehicleStatus.gasModeRange', {
                      type: 'state',
                      common: {
                          name: 'Vehicle total available range for gas',
                          type: 'number',
                          role: 'indicator',
                          read: true,
                          write: false,
                      },
                      native: {},
                  });
          
                  //Charge
                  await this.setObjectNotExistsAsync(vin + '.vehicleStatus.battery.charge_limit_slow', {
                      type: 'state',
                      common: {
                          name: 'Vehicle charge limit for slow charging',
                          type: 'number',
                          role: 'indicator',
                          read: true,
                          write: true,
                      },
                      native: {},
                  });
                  this.subscribeStates(vin + '.vehicleStatus.battery.charge_limit_slow');
          
                  await this.setObjectNotExistsAsync(vin + '.vehicleStatus.battery.charge_limit_fast', {
                      type: 'state',
                      common: {
                          name: 'Vehicle charge limit for fast charging',
                          type: 'number',
                          role: 'indicator',
                          read: true,
                          write: true,
                      },
                      native: {},
                  });
                  this.subscribeStates(vin + '.vehicleStatus.battery.charge_limit_fast');
          
                  await this.setObjectNotExistsAsync(vin + '.vehicleStatus.battery.minutes_to_charged', {
                      type: 'state',
                      common: {
                          name: 'Vehicle minutes to charged',
                          type: 'number',
                          role: 'indicator',
                          read: true,
                          write: true,
                      },
                      native: {},
                  });
          
                  //Battery
                  await this.setObjectNotExistsAsync(vin + '.vehicleStatus.battery.soc', {
                      type: 'state',
                      common: {
                          name: 'Vehicle battery state of charge',
                          type: 'number',
                          role: 'indicator',
                          read: true,
                          write: false,
                      },
                      native: {},
                  });
          
                  await this.setObjectNotExistsAsync(vin + '.vehicleStatus.battery.charge', {
                      type: 'state',
                      common: {
                          name: 'Vehicle charging',
                          type: 'boolean',
                          role: 'indicator',
                          read: true,
                          write: false,
                      },
                      native: {},
                  });
          
                  await this.setObjectNotExistsAsync(vin + '.vehicleStatus.battery.plugin', {
                      type: 'state',
                      common: {
                          name: 'Charger connected (UNPLUGED = 0, FAST = 1, PORTABLE = 2, STATION = 3)',
                          type: 'number',
                          role: 'indicator',
                          read: true,
                          write: false,
                      },
                      native: {},
                  });
          
                  await this.setObjectNotExistsAsync(vin + '.vehicleStatus.battery.soc-12V', {
                      type: 'state',
                      common: {
                          name: 'Vehicle 12v battery state of charge',
                          type: 'number',
                          role: 'indicator',
                          read: true,
                          write: false,
                      },
                      native: {},
                  });
          
                  await this.setObjectNotExistsAsync(vin + '.vehicleStatus.battery.state-12V', {
                      type: 'state',
                      common: {
                          name: 'Vehicle 12v battery State',
                          type: 'number',
                          role: 'indicator',
                          read: true,
                          write: false,
                      },
                      native: {},
                  });
          
                  //Bereich vehicleLocation
                  await this.setObjectNotExistsAsync(vin + '.vehicleLocation.lat', {
                      type: 'state',
                      common: {
                          name: 'Vehicle position latitude',
                          type: 'string',
                          role: 'indicator',
                          read: true,
                          write: false,
                      },
                      native: {},
                  });
          
                  await this.setObjectNotExistsAsync(vin + '.vehicleLocation.lon', {
                      type: 'state',
                      common: {
                          name: 'Vehicle position longitude',
                          type: 'string',
                          role: 'indicator',
                          read: true,
                          write: false,
                      },
                      native: {},
                  });
          
                  await this.setObjectNotExistsAsync(vin + '.vehicleLocation.speed', {
                      type: 'state',
                      common: {
                          name: 'Vehicle speed',
                          type: 'number',
                          role: 'indicator',
                          read: true,
                          write: false,
                      },
                      native: {},
                  });
          
                  //Bereich Odometer
                  await this.setObjectNotExistsAsync(vin + '.odometer.value', {
                      type: 'state',
                      common: {
                          name: 'Odometer value',
                          type: 'number',
                          role: 'indicator',
                          read: true,
                          write: false,
                      },
                      native: {},
                  });
          
                  await this.setObjectNotExistsAsync(vin + '.odometer.unit', {
                      type: 'state',
                      common: {
                          name: 'Odometer unit',
                          type: 'number',
                          role: 'indicator',
                          read: true,
                          write: false,
                      },
                      native: {},
                  });
              }
              async cleanObjects() {
                  const controlState = await this.getObjectAsync('control.charge');
          
                  if (controlState) {
                      await this.delObjectAsync('control', { recursive: true });
                      await this.delObjectAsync('odometer', { recursive: true });
                      await this.delObjectAsync('vehicleLocation', { recursive: true });
                      await this.delObjectAsync('vehicleStatus', { recursive: true });
                  }
              }
          
              getCircularReplacer() {
                  const seen = new WeakSet();
                  return (key, value) => {
                      if (typeof value === 'object' && value !== null) {
                          if (seen.has(value)) {
                              return;
                          }
                          seen.add(value);
                      }
                      return value;
                  };
              }
          
              getCelsiusFromTempcode(tempCode) {
                  // create a range
                  const tempRange = [];
                  //Range for EU
                  for (let i = 14; i <= 30; i += 0.5) {
                      tempRange.push(i);
                  }
          
                  // get the index
                  const tempIndex = parseInt(tempCode, 16);
          
                  // return the relevant celsius temp
                  return tempRange[tempIndex];
              }
          }
          
          if (require.main !== module) {
              // Export the constructor in compact mode
              /**
               * @param {Partial<utils.AdapterOptions>} [options={}]
               */
              module.exports = (options) => new Bluelink(options);
          } else {
              // otherwise start the instance directly
              new Bluelink();
          }
          

          Diese Punkte haben sich zum original geändert:

          • es hatte sich ein kleiner Fehler eingeschlichen der den Wert des neuen States "force_update" das @arteck mit der Version 2.2.7 eingeführt hat nicht richtig an "Bluelinky" übergeben hat (hier fehlte ein .val)
          • sowohl die "Full Status" Abrage als auch die "Fallback" Abfrage kann nun mittels des neuen States "force_update" geschaltet werden, so dass man stets wählen kann ob die Daten nur vom Hyundai-Server kommen (false) oder direkt vom Auto (true) geholt werden.
          • Beim Start des Adapters wird die Einstellung des States "force_update" übergangen und die Daten auf jeden Fall vom PKW geholt, so dass die Daten auf jeden Fall top aktuell sind. Danach muss dann jeder über den State "force_update" entscheiden was er will.
          • Der Zeitstempel "lastInfoUpdate" wird nun erst nach einem erfolgreichen Update gesetzt, so dass man hieran sehen kann ob und wann das letzte erfolgreiche Update erfolgt ist.
          • @Michaelnorge den hard-gecodeten Wert für die Batterieüberwachung habe ich von 88 auf 60 geändert. Vielleicht könnte man das ja mal in die Adaptereinstellungen integrieren, so dass man diesen Wert individuell anpassen kann.

          (Ich hatte das hier schon mal geschrieben: Ich kann eigentlich kein Java programmieren. Ich kann zwar ein Script lesen und verstehe auch zum großen Teil was es macht das war's dann aber auch schon. D.h. die Änderungen in meiner "main.js" sind durch probieren, copy-paste und ein weinig nachlesen entstanden. Will heißen, das Script läuft zwar prima, ist aber nicht unbedingt programmiertechnisch perfekt.)

          Ich selbst nutze die Einstellung FALSE beim State "force_update" mit 360 Abfragen pro Tag (also alle 4 min. eine Abfrage). Mehr Abfragen (alle 3 min. oder mehr) führten bei mir zu einer Fehlermeldung des Hyundai-Servers, dass ich zu viele Abfragen pro Tag an den Server stellen würde. Dann ging sogar die App nicht mehr...
          Sobald ich irgendwie registriere, dass mein Auto geladen wird (Ioniq 5) z.B. Rückmeldung bei der Server Abfrage oder Meldung durch meine Wall-Box, schalte ich per Blockly Script den State "force_update" um auf true, so dass die Daten direkt vom PKW geholt werden. Nach Beendigung des Ladevorgangs schalte ich dann wieder zurück auf false. Das funktioniert super und belastet halt die 12V Batterie so gut wie gar nicht mehr.

          M Offline
          M Offline
          Michaelnorge
          schrieb am zuletzt editiert von
          #961

          @stefan-cloer Super Arbeit (denke ich, ich kann nicht coden :blush: ) - Kann das irgendwie integriert werden und dann "fertig" bei GitHub angeboten werden? :grin:

          –--------------------------------------------------------------------------------------

          • Smart mit: Rasp 4B / ioBroker / Conbee2 / Trådfri / Xiaomi / HUE / Logitech Harmony / Aqara / Easee Wallbox / Hyundai Ioniq / Alexa / Google Home / Fully Kiosk / VIS
          1 Antwort Letzte Antwort
          0
          • S stefan.cloer

            @arteck
            Ich habe dann Anfang der Woche auch mal den Wechsel von meiner selbst angepassten "main.js" des Adapters auf die Version 2.2.8 gemacht. Ich habe also die 2.2.7 übersprungen.
            Nach der Installation von 2.2.8 funktionierte die Abfrage des Autos leider bei mir auch nicht mehr so schön wie sie zuvor bei meiner selbst gemachten Anpassung lief. Ich hatte auch sehr schnell den Verdacht, dass sich in der 2.2.8 ein Fehler befindet oder zumindest etwas anders lief als bei meiner eigenen Version. Daraufhin habe ich mal die neue "main.js" durchgeackert und tatsächlich ein paar Dinge gefunden die meiner Meinung nach nicht korrekt sind bzw. aus meiner Sicht besser gelöst werden könnten. (Das soll keine Kritik an der tollen Arbeit von @arteck und @Newan sein, ich hatte einfach nur gemerkt, dass sich da was anders verhält als zuvor.)
            Ich habe daraufhin noch mal ein paar Anpassungen an der "main.js" der Version 2.2.8 vorgenommen. Jetzt läuft sie wieder zu meiner vollsten Zufriedenheit. Gerne kann ich das mit euch teilen:

            'use strict';
            
            const utils = require('@iobroker/adapter-core');
            const bluelinky = require('bluelinky');
            const Json2iob = require('./lib/json2iob');
            let force_update = {};   
            force_update.val = true;   
            
            const adapterIntervals = {}; //halten von allen Intervallen
            let request_count = 48; // halbstündig sollte als Standardeinstellung reichen (zu häufige Abfragen entleeren die Batterie spürbar)
            let client;
            
            let slow_charging;
            let fast_charging;
            
            const POSSIBLE_CHARGE_LIMIT_VALUES = [50, 60, 70, 80, 90, 100];
            
            class Bluelink extends utils.Adapter {
                /**
                 * @param {Partial<utils.AdapterOptions>} [options={}]
                 */
                constructor(options) {
                    super({
                        ...options,
                        name: 'bluelink',
                    });
            
                    this.on('ready', this.onReady.bind(this));
                    this.on('stateChange', this.onStateChange.bind(this));
                    // this.on('objectChange', this.onObjectChange.bind(this));
                    // this.on('message', this.onMessage.bind(this));
                    this.on('unload', this.onUnload.bind(this));
                    this.vehiclesDict = {};
                    this.batteryState12V = {};
                    this.vehicles = [];
                    this.json2iob = new Json2iob(this);
                    adapterIntervals.evHistoryInterval = null;
                    this.countError = 0;
                }
            
                //Start Adapter
                async onReady() {
                    //first check account settings
                    if (this.config.request < 1) {
                        this.log.warn('Request is under 1 -> got to default 100');
                    } else {
                        request_count = this.config.request;
                    }
            
                    if (this.config.username == '') {
                        this.log.error('No Username set');
                    } else {
                        //Start logic with login
                        this.login();
                    }
                }
            
                /**
                 * Is called when adapter shuts down - callback has to be called under any circumstances!
                 * @param {() => void} callback
                 */
                onUnload(callback) {
                    try {
                        clearTimeout(adapterIntervals.readAllStates);
                        clearInterval(adapterIntervals.evHistoryInterval);
                        this.log.info('Adapter bluelink cleaned up everything...');
                        callback();
                    } catch (e) {
                        callback();
                    }
                }
            
                async onStateChange(id, state) {
                    if (state) {
                        if (id.indexOf('.control.') === -1) {
                            return;
                        }
                        this.log.debug('New Event for state: ' + JSON.stringify(state));
                        this.log.debug('ID: ' + JSON.stringify(id));
            
                        const vin = id.split('.')[2];
                        const vehicle = this.vehiclesDict[vin];
                        const tmpControl = id.split('.')[4];
                        let response;
                        switch (tmpControl) {
                            case 'lock':
                                this.log.info('Starting lock for vehicle');
                                response = await vehicle.lock();
                                this.log.info(response);
                                break;
                            case 'unlock':
                                this.log.info('Starting unlock for vehicle');
                                response = await vehicle.unlock();
                                this.log.info(response);
                                break;
                            case 'start':
                                this.log.info('Starting clima for vehicle');
            
                                let airCtrl = await this.getStateAsync(`${vin}.control.set.airCtrl`);                
                                let airTempC = await this.getStateAsync(`${vin}.control.set.airTemp`);
                                let airTempF = (airTempC.val * 9/5) + 32;
                                let defrost = await this.getStateAsync(`${vin}.control.set.defrost`);
                                let heating = await this.getStateAsync(`${vin}.control.set.heating`);
                              
                                try {
                                    response = await vehicle.start({
                                        airCtrl: airCtrl.val,
                                        igniOnDuration: 10,
                                        airTempvalue: airTempF,
                                        defrost: defrost.val,
                                        heating1: heating.val,
                                    });
                                } catch (err) {
                                    this.log.error(JSON.stringify(err));                    
                                }    
                                break;
                            case 'stop':
                                this.log.info('Stop clima for vehicle');
                                response = await vehicle.stop();
                                this.log.debug(JSON.stringify(response));
                                break;
                            case 'force_refresh':
                                this.log.info('Forcing refresh');
                                //Force refresh for new states
                                this.readStatus(true);
                                break;
                            case 'force_update':
            			        force_update = await this.getStateAsync(`${vin}.control.force_update`);   
            	            	if(force_update.val) {
                	                this.log.info('Update method for ' + vin + ' changed to "directly from the car"');
                    	        } else {
                        	        this.log.info('Update method for ' + vin + ' changed to "from the server"');
                            	}
                                break;
                            case 'charge':
                                this.log.info('Start charging');
                                response = await vehicle.startCharge();
                                break;
                            case 'charge_stop':
                                this.log.info('Stop charging');
                                response = await vehicle.stopCharge();
                                break;
                            case 'battery':
                                if (!state.ack) {
                                    if (!POSSIBLE_CHARGE_LIMIT_VALUES.includes(state.val)) {
                                        this.log.error(`Charge target values are limited to ${POSSIBLE_CHARGE_LIMIT_VALUES.join(', ')}`);
                                    } else {
                                        this.log.info('Set new charging options');
                                        const charge_option = { fast: fast_charging, slow: slow_charging };
                                        if (tmpControl[4] == 'charge_limit_fast') {
                                            //set fast charging
                                            this.log.debug('Set fast charging');
                                            charge_option.fast = state.val;
                                        } else {
                                            //set slow charging
                                            this.log.debug('Set slow charging');
                                            charge_option.slow = state.val;
                                        }
                                        response = await vehicle.setChargeTargets(charge_option);
                                        this.log.debug(JSON.stringify(response));
                                    }
                                }
                                break;
                            default:
                                this.log.error('No command for Control found for: ' + id);
                        }
                    }
                }
            
                /**
                 * Funktion to login in bluelink / UVO
                 */
                login() {
                    try {
                        this.log.info('Login to api');
                        const tmpConfig = {
                            username: this.config.username,
                            password: this.config.client_secret,
                            pin: this.config.client_secret_pin,
                            brand: this.config.brand,
                            region: 'EU', //set over GUI next time
                            language:  this.config.language,
                        };
            
                        // @ts-ignore
                        client = new bluelinky(tmpConfig);
            
                        client.on('ready', async (vehicles) => {
                            // wir haben eine Verbindung und haben Autos
                            this.log.info(vehicles.length + ' Vehicles found');
                            this.log.debug(JSON.stringify(vehicles, this.getCircularReplacer()));
            
                            this.vehicles = vehicles;
                            for (const vehicle of vehicles) {
                                const vin = vehicle.vehicleConfig.vin;
                                this.vehiclesDict[vin] = vehicle;
                                await this.setObjectNotExistsAsync(vin, {
                                    type: 'device',
                                    common: {
                                        name: vehicle.vehicleConfig.nickname,
                                    },
                                    native: {},
                                });
            
                                await this.setControlObjects(vin);
                                await this.setStatusObjects(vin);
            
                                await this.setObjectNotExistsAsync(vin + '.general', {
                                    type: 'channel',
                                    common: {
                                        name: 'General Information',
                                    },
                                    native: {},
                                });
                                await this.json2iob.parse(vin + '.general', vehicle.vehicleConfig);
                                if (this.config.evHistory) {
                                    await this.receiveEVInformation(vehicle, vin);
                                    adapterIntervals.evHistoryInterval = setInterval(() => {
                                        this.receiveEVInformation(vehicle, vin);
                                    }, 24 * 60 * 60 * 1000); //24h
                                }
                            }
                            //start time cycle
                            await this.readStatus();
            
                            //clean legacy states
                            this.cleanObjects();
                        });
            
                        client.on('error', async (err) => {
                            // something went wrong with login
                            this.log.debug('Error on Api login');
                            this.log.error(err);
                            this.log.error('Please logout in the app and relogin in the app');
                        });
                    } catch (error) {
                        this.log.error('Error in login/on function');
                        if (typeof error === 'string') {
                            this.log.error(error);
                        } else if (error instanceof Error) {
                            this.log.error(error.message);
                        }
                    }
                }
            
                //read new sates from vehicle
                async readStatus(force = false) {
                    //read new verhicle status
                    for (const vehicle of this.vehicles) {
                        const vin = vehicle.vehicleConfig.vin;
            
                        this.log.debug('Read new status from api for ' + vin);
                        if (this.batteryState12V[vin] && this.batteryState12V[vin] < 60) {
                            this.log.warn('12V Battery state is low: ' + this.batteryState12V[vin] + '%. Recharge to prevent damage!');
                            if (this.config.protectAgainstDeepDischarge && !force) {
                                this.log.warn('Auto Refresh is disabled, only use force refresh to reenable refresh if you are willing to risk your battery');
                                continue;
                            }
                        }
                        try {
                            let newStatus;
            
                        	if(force_update.val) {
                                this.log.info('Read new update for ' + vin + ' directly from the car');
                            } else {
                                this.log.info('Read new update for ' + vin + ' from the server');
                            }
                            	
                        	try {
                                newStatus = await vehicle.fullStatus({
                                    refresh: force_update.val,
                                    parsed: true,
                                });
                                //set all values
                                this.log.debug('Set new full status for ' + vin);
                                this.log.debug('RAW ' + JSON.stringify(newStatus));
                                
                                // raw data
                                await this.json2iob.parse(vin + '.vehicleStatusRaw', newStatus);
                                
                                await this.setNewFullStatus(newStatus, vin);
                                if (newStatus.vehicleStatus && newStatus.vehicleStatus.battery && newStatus.vehicleStatus.battery.batSoc) {
                                    this.log.debug('Set ' + newStatus.vehicleStatus.battery.batSoc + ' battery state for ' + vin);
                                    this.batteryState12V[vin] = newStatus.vehicleStatus.battery.batSoc;
                                }
            
                            } catch (error) {
                                if (typeof error === 'string') {
                                    this.log.error('Error on API-Request GetFullStatus');
                                    this.log.error(error);
                                    //TODO option abfragen
                                } else {
                                    //if(error.source.statusCode == 503) {
                                    this.log.info('Error on API-Full-Status - Fallback GetNormalStatus');
            
                                    //Abfrage Full hat nicht gekalppt. Haben wir einen Fallback?
                                    newStatus = await vehicle.status({
                                        refresh: force_update.val,
                                        parsed: true,
                                    });
                                	this.log.debug('Set new GetNormalStatus for ' + vin);
                                    this.log.debug(JSON.stringify(newStatus));
            
                                    await this.setNewStatus(newStatus, vin);
                                    if (newStatus.engine && newStatus.engine.batteryCharge12v) {
                                        this.log.debug('Set ' + newStatus.engine.batteryCharge12v + ' battery state for ' + vin);
                                        this.batteryState12V[vin] = newStatus.engine.batteryCharge12v;
                                    }
                                }
                            }
            
                            //Abfrage war erfolgreich, lösche ErrorCounter
                            this.countError = 0;
            
            		        force_update = await this.getStateAsync(`${vin}.control.force_update`);
                            this.log.info('Update for ' + vin + ' successfull');
            	  	       // last update
                	        await this.setStateAsync(`${vin}.lastInfoUpdate`, Number(Date.now()), true);
                        
                        } catch (error) {
                            this.countError += 1;  // add 1
                           
                            this.log.error('Error on API-Request Status, ErrorCount:' + this.countError);
                            if (typeof error === 'string') {
                                this.log.error(error);
                            } else if (error instanceof Error) {
                                this.log.error(error.message);
                            }
                        }
            
                        await this.setStateAsync(`${vin}.error_counter`, this.countError, true);
                        
                        if (this.countError > this.config.errorCounter) {
                            //Error counter over x erros, restart Adapter to fix te API Token
                            this.restart();
                        }
                    }
                
                    //set ne cycle
                    if (force) {
                        clearTimeout(adapterIntervals.readAllStates);
                    }
                    adapterIntervals.readAllStates = setTimeout(this.readStatus.bind(this), ((24 * 60) / request_count) * 60000);
                }
            
                async receiveEVInformation(vehicle, vin) {
                    try {
                        const driveHistory = await vehicle.driveHistory();
                        this.log.debug('driveHistory-Data: ' + JSON.stringify(driveHistory));
                        
                        if (driveHistory != undefined) { 
                        
                            await this.setObjectNotExistsAsync(vin + '.driveHistory', {
                                type: 'channel',
                                common: {
                                    name: 'drive history',
                                },
                                native: {},
                            });
                            await this.json2iob.parse(vin + '.driveHistory', driveHistory, { preferedArrayName: 'rawDate' });
                            const monthlyReport = await vehicle.monthlyReport();
                            await this.setObjectNotExistsAsync(vin + '.monthlyReport', {
                                type: 'channel',
                                common: {
                                    name: 'monthly report',
                                },
                                native: {},
                            });
                            await this.json2iob.parse(vin + '.monthlyReport', monthlyReport);
                            const tripInfo = await vehicle.tripInfo({ year: new Date().getFullYear(), month: new Date().getMonth() + 1 });
                            await this.setObjectNotExistsAsync(vin + '.tripInfo', {
                                type: 'channel',
                                common: {
                                    name: 'trip information',
                                },
                                native: {},
                            });
                            await this.json2iob.parse(vin + '.tripInfo', tripInfo);
                        }
                    } catch (error) {
                        this.log.error('EV History fetching failed');
                        if (typeof error === 'string') {
                            this.log.error(error);
                        } else if (error instanceof Error) {
                            this.log.error(error.message);
                        }
                    }
                }
            
                //Set new values to ioBroker for normal Status
                async setNewStatus(newStatus, vin) {
                    //chassis
                    await this.setStateAsync(vin + '.vehicleStatus.doorLock', { val: newStatus.chassis.locked, ack: true });
                    await this.setStateAsync(vin + '.vehicleStatus.trunkOpen', { val: newStatus.chassis.trunkOpen, ack: true });
                    await this.setStateAsync(vin + '.vehicleStatus.hoodOpen', { val: newStatus.chassis.hoodOpen, ack: true });
            
                    //chassis/doors
                    this.checkDoor(vin, newStatus.chassis.openDoors);
            
                    //chassis/tirePressure
                 //   if (newStatus.chassis.tirePressureWarningLamp != undefined) {
                 //
                 //   }
            
                    //climate
                    await this.setStateAsync(vin + '.vehicleStatus.airCtrlOn', { val: newStatus.climate.active, ack: true });
                    await this.setStateAsync(vin + '.vehicleStatus.airTemp', { val: newStatus.climate.temperatureSetpoint, ack: true });
                    await this.setStateAsync(vin + '.vehicleStatus.steerWheelHeat', { val: newStatus.climate.steeringwheelHeat, ack: true });
                    //await this.setStateAsync(vin + '.vehicleStatus.sideBackWindowHeat', { val: newStatus.climate.sideBackWindowHeat, ack: true });
            
                    //Engine
                    await this.setStateAsync(vin + '.vehicleStatus.battery.soc', { val: newStatus.engine.batteryChargeHV, ack: true });
                    await this.setStateAsync(vin + '.vehicleStatus.battery.charge', { val: newStatus.engine.charging, ack: true });       
                    await this.setStateAsync(vin + '.vehicleStatus.battery.soc-12V', { val: newStatus.engine.batteryCharge12v, ack: true });
                }
            
                //Set new values to ioBroker
                async setNewFullStatus(newStatus, vin) {
                    await this.setStateAsync(vin + '.vehicleStatus.airCtrlOn', { val: newStatus.vehicleStatus.airCtrlOn, ack: true });
                    await this.setStateAsync(vin + '.vehicleStatus.airTemp', {
                        val: this.getCelsiusFromTempcode(newStatus.vehicleStatus.airTemp.value),
                        ack: true,
                    });
            
                    //Charge
            
                    //Bei Kia sind die Werte in einer targetSOClist
                    if (newStatus.vehicleStatus.evStatus != undefined) {
                        if (newStatus.vehicleStatus.evStatus.reservChargeInfos.targetSOClist != undefined) {
                            if (newStatus.vehicleStatus.evStatus.reservChargeInfos.targetSOClist[0].plugType == 1) {
                                //Slow  = 1  -> Index 0 ist slow
                                await this.setStateAsync(vin + '.vehicleStatus.battery.charge_limit_slow', {
                                    val: newStatus.vehicleStatus.evStatus.reservChargeInfos.targetSOClist[0].targetSOClevel,
                                    ack: true,
                                });
                                slow_charging = newStatus.vehicleStatus.evStatus.reservChargeInfos.targetSOClist[0].targetSOClevel;
                                await this.setStateAsync(vin + '.vehicleStatus.battery.charge_limit_fast', {
                                    val: newStatus.vehicleStatus.evStatus.reservChargeInfos.targetSOClist[1].targetSOClevel,
                                    ack: true,
                                });
                                fast_charging = newStatus.vehicleStatus.evStatus.reservChargeInfos.targetSOClist[1].targetSOClevel;
                            } else {
                                //fast  = 0  -> Index 0 ist fast
                                await this.setStateAsync(vin + '.vehicleStatus.battery.charge_limit_slow', {
                                    val: newStatus.vehicleStatus.evStatus.reservChargeInfos.targetSOClist[1].targetSOClevel,
                                    ack: true,
                                });
                                slow_charging = newStatus.vehicleStatus.evStatus.reservChargeInfos.targetSOClist[1].targetSOClevel;
                                await this.setStateAsync(vin + '.vehicleStatus.battery.charge_limit_fast', {
                                    val: newStatus.vehicleStatus.evStatus.reservChargeInfos.targetSOClist[0].targetSOClevel,
                                    ack: true,
                                });
                                fast_charging = newStatus.vehicleStatus.evStatus.reservChargeInfos.targetSOClist[0].targetSOClevel;
                            }
                        } else {
                            //Bei Hyundai sieht es anders aus:
                        }
            
                        //Nur für Elektro Fahrzeuge - Battery
                        await this.setStateAsync(vin + '.vehicleStatus.dte', {
                            val: newStatus.vehicleStatus.evStatus.drvDistance[0].rangeByFuel.totalAvailableRange.value,
                            ack: true,
                        });
                        await this.setStateAsync(vin + '.vehicleStatus.evModeRange', {
                            val: newStatus.vehicleStatus.evStatus.drvDistance[0].rangeByFuel.evModeRange.value,
                            ack: true,
                        });
                        if (newStatus.vehicleStatus.evStatus.drvDistance[0].rangeByFuel.gasModeRange != undefined) {
                            //Only for PHEV
                            await this.setStateAsync(vin + '.vehicleStatus.gasModeRange', {
                                val: newStatus.vehicleStatus.evStatus.drvDistance[0].rangeByFuel.gasModeRange.value,
                                ack: true,
                            });
                        }
            
                        await this.setStateAsync(vin + '.vehicleStatus.battery.soc', { val: newStatus.vehicleStatus.evStatus.batteryStatus, ack: true });
                        await this.setStateAsync(vin + '.vehicleStatus.battery.charge', { val: newStatus.vehicleStatus.evStatus.batteryCharge, ack: true });
                        await this.setStateAsync(vin + '.vehicleStatus.battery.plugin', { val: newStatus.vehicleStatus.evStatus.batteryPlugin, ack: true });
            
                        //Ladezeit anzeigen, da noch nicht klar welche Werte
                        await this.setStateAsync(vin + '.vehicleStatus.battery.minutes_to_charged', {
                            val: newStatus.vehicleStatus.evStatus.remainTime2.atc.value,
                            ack: true,
                        });
                        this.log.debug('Folgende Ladezeiten Moeglichkeiten wurden gefunden:');
                        this.log.debug(JSON.stringify(newStatus.vehicleStatus.evStatus.remainTime2));
                    } else {
                        //Kein Elektromodell, Diesel etc
                        await this.setStateAsync(vin + '.vehicleStatus.dte', { val: newStatus.vehicleStatus.dte.value, ack: true });
                    }
            
                    // nur für Kia              
                    if (newStatus.vehicleStatus.battery != undefined) {
                        await this.setStateAsync(vin + '.vehicleStatus.battery.soc-12V', { val: newStatus.vehicleStatus.battery.batSoc, ack: true });
                        await this.setStateAsync(vin + '.vehicleStatus.battery.state-12V', { val: newStatus.vehicleStatus.battery.batState, ack: true });
                    }
            
                    //Location
                    if (newStatus.vehicleLocation != undefined) {
                        //#47 KIA Seed have no vehicleLocation
                        if (newStatus.vehicleLocation.coord != undefined) {
                            const latitude = newStatus.vehicleLocation.coord.lat;
                            const longitude = newStatus.vehicleLocation.coord.lon;
                            await this.setStateAsync(vin + '.vehicleLocation.lat', { val: latitude, ack: true });
                            await this.setStateAsync(vin + '.vehicleLocation.lon', { val: longitude, ack: true });
                            await this.setStateAsync(vin + '.vehicleLocation.speed', { val: newStatus.vehicleLocation.speed.value, ack: true });
                        }
                    }
            
                    //Odometer
                    await this.setStateAsync(vin + '.odometer.value', { val: newStatus.odometer.value, ack: true });
                    await this.setStateAsync(vin + '.odometer.unit', { val: newStatus.odometer.unit, ack: true });
            
                    //open / door
                    await this.setStateAsync(vin + '.vehicleStatus.doorLock', { val: newStatus.vehicleStatus.doorLock, ack: true });
                    await this.setStateAsync(vin + '.vehicleStatus.trunkOpen', { val: newStatus.vehicleStatus.trunkOpen, ack: true });
                    await this.setStateAsync(vin + '.vehicleStatus.hoodOpen', { val: newStatus.vehicleStatus.hoodOpen, ack: true });
            
                    this.checkDoor(vin, newStatus.vehicleStatus.doorOpen);
            
                    //status parameter
                    await this.setStateAsync(vin + '.vehicleStatus.airCtrlOn', { val: newStatus.vehicleStatus.airCtrlOn, ack: true });
                    await this.setStateAsync(vin + '.vehicleStatus.smartKeyBatteryWarning', { val: newStatus.vehicleStatus.smartKeyBatteryWarning, ack: true });
                    await this.setStateAsync(vin + '.vehicleStatus.washerFluidStatus', { val: newStatus.vehicleStatus.washerFluidStatus, ack: true });
                    await this.setStateAsync(vin + '.vehicleStatus.breakOilStatus', { val: newStatus.vehicleStatus.breakOilStatus, ack: true });
                    await this.setStateAsync(vin + '.vehicleStatus.steerWheelHeat', { val: newStatus.vehicleStatus.steerWheelHeat, ack: true });
                    await this.setStateAsync(vin + '.vehicleStatus.sideBackWindowHeat', { val: newStatus.vehicleStatus.sideBackWindowHeat, ack: true });
                }
            
                async checkDoor(vin, doors) {
                    if (doors != undefined) {
                        let frontLeft = doors.frontLeft;
                        let frontRight = doors.frontRight;
                        let backLeft = doors.backLeft;
                        let backRight = doors.backRight;
            
                    // HEV hyundai send 0 but we need boolean
                        if (typeof frontLeft == 'number') {
                            frontLeft = frontLeft == 0 ? false : true;
                        }
            
                        if (typeof frontRight == 'number') {
                            frontRight = frontRight == 0 ? false : true;
                        }
            
                        if (typeof backLeft == 'number') {
                            backLeft = backLeft == 0 ? false : true;
                        }
            
                        if (typeof backRight == 'number') {
                            backRight = backRight == 0 ? false : true;
                        }
            
                        await this.setStateAsync(vin + '.vehicleStatus.doorOpen.frontLeft', { val: frontLeft, ack: true });
                        await this.setStateAsync(vin + '.vehicleStatus.doorOpen.frontRight', { val: frontRight, ack: true });
                        await this.setStateAsync(vin + '.vehicleStatus.doorOpen.backLeft', { val: backLeft, ack: true });
                        await this.setStateAsync(vin + '.vehicleStatus.doorOpen.backRight', { val: backRight, ack: true });
                    }
                }
            
                /**
                 * Functions to create the ioBroker objects
                 */
            
                async setControlObjects(vin) {
                    await this.setObjectNotExistsAsync(vin + '.control.charge', {
                        type: 'state',
                        common: {
                            name: 'Start charging',
                            type: 'boolean',
                            role: 'button',
                            read: true,
                            write: true,
                        },
                        native: {},
                    });
                    this.subscribeStates(vin + '.control.charge');
            
                    await this.setObjectNotExistsAsync(vin + '.control.charge_stop', {
                        type: 'state',
                        common: {
                            name: 'Stop charging',
                            type: 'boolean',
                            role: 'button',
                            read: true,
                            write: true,
                        },
                        native: {},
                    });
                    this.subscribeStates(vin + '.control.charge_stop');
            
                    await this.setObjectNotExistsAsync(vin + '.control.lock', {
                        type: 'state',
                        common: {
                            name: 'Lock the vehicle',
                            type: 'boolean',
                            role: 'button',
                            read: true,
                            write: true,
                        },
                        native: {},
                    });
                    this.subscribeStates(vin + '.control.lock');
            
                    await this.setObjectNotExistsAsync(vin + '.control.unlock', {
                        type: 'state',
                        common: {
                            name: 'Unlock the vehicle',
                            type: 'boolean',
                            role: 'button',
                            read: true,
                            write: true,
                        },
                        native: {},
                    });
                    this.subscribeStates(vin + '.control.unlock');
            
                    await this.setObjectNotExistsAsync(vin + '.control.start', {
                        type: 'state',
                        common: {
                            name: 'Start clima for the vehicle',
                            type: 'boolean',
                            role: 'button',
                            read: true,
                            write: true,
                        },
                        native: {},
                    });
                    this.subscribeStates(vin + '.control.start');
                    
                    await this.setObjectNotExistsAsync(vin + '.control.set.airTemp', {
                        type: 'state',
                        common: {
                            name: 'set air temperature for clima',
                            type: 'number',
                            role: 'value.temperature',
                            read: true,
                            write: true,
                            def: 20,
                        },
                        native: {},
                    });
                    
                    await this.setObjectNotExistsAsync(vin + '.control.set.defrost', {
                        type: 'state',
                        common: {
                            name: 'set defrost function for clima',
                            type: 'boolean',
                            role: 'state',
                            read: true,
                            write: true,
                            def: false,
                        },
                        native: {},
                    });
            
                    await this.setObjectNotExistsAsync(vin + '.control.set.heating', {
                        type: 'state',
                        common: {
                            name: 'set heating function for clima',
                            type: 'number',
                            role: 'state',
                            read: true,
                            write: true,
                            def: 0,
                        },
                        native: {},
                    });
            
                    await this.setObjectNotExistsAsync(vin + '.control.set.airCtrl', {
                        type: 'state',
                        common: {
                            name: 'set airCtrl function for clima',
                            type: 'boolean',
                            role: 'state',
                            read: true,
                            write: true,
                            def: false,
                        },
                        native: {},
                    });
                    
                    await this.setObjectNotExistsAsync(vin + '.control.stop', {
                        type: 'state',
                        common: {
                            name: 'Stop clima for the vehicle',
                            type: 'boolean',
                            role: 'button',
                            read: true,
                            write: true,
                        },
                        native: {},
                    });
                    this.subscribeStates(vin + '.control.stop');
            
                    await this.setObjectNotExistsAsync(vin + '.control.force_refresh', {
                        type: 'state',
                        common: {
                            name: 'Force refresh vehicle status',
                            type: 'boolean',
                            role: 'button',
                            read: true,
                            write: true,
                        },
                        native: {},
                    });
                    this.subscribeStates(vin + '.control.force_refresh');
                    
                    await this.setObjectNotExistsAsync(vin + '.control.force_update', {
                        type: 'state',
                        common: {
                            name: 'Force update state for force refresh',
                            type: 'boolean',
                            role: 'button',
                            read: true,
                            write: true,
                            def: true,
                        },
                        native: {},
                    });         
                    this.subscribeStates(vin + '.control.force_update');
               }
            
               async setStatusObjects(vin) {          
                    await this.setObjectNotExistsAsync(`${vin}.lastInfoUpdate`, {
                        type: 'state',
                        common: {
                            name: 'Date/Time of last information update',
                            type: 'number',
                            role: 'value.time',
                            read: true,
                            write: false
                        },
                        native: {},
                    });
                 
                    await this.setObjectNotExistsAsync(`${vin}.error_counter`, {
                        type: 'state',
                        common: {
                            name: 'error_counter',
                            type: 'number',
                            role: 'state',
                            read: true,
                            write: false,
                            def: 0,
                        },
                        native: {},
                    });
                    
                    await this.setObjectNotExistsAsync(vin + '.vehicleStatusRaw', {
                        type: 'channel',
                        common: {
                            name: 'Unformatted vehicle status',               
                        },
                        native: {},
                    });
                    
                    
                    //Bereicht vehicleStatus
                    await this.setObjectNotExistsAsync(vin + '.vehicleStatus.doorLock', {
                        type: 'state',
                        common: {
                            name: 'Vehicle doors locked',
                            type: 'boolean',
                            role: 'indicator',
                            read: true,
                            write: false,
                        },
                        native: {},
                    });
            
                    await this.setObjectNotExistsAsync(vin + '.vehicleStatus.trunkOpen', {
                        type: 'state',
                        common: {
                            name: 'Trunk open',
                            type: 'boolean',
                            role: 'indicator',
                            read: true,
                            write: false,
                        },
                        native: {},
                    });
            
                    await this.setObjectNotExistsAsync(vin + '.vehicleStatus.hoodOpen', {
                        type: 'state',
                        common: {
                            name: 'Hood open',
                            type: 'boolean',
                            role: 'indicator',
                            read: true,
                            write: false,
                        },
                        native: {},
                    });
            
                    //Doors open
                    await this.setObjectNotExistsAsync(vin + '.vehicleStatus.doorOpen.frontLeft', {
                        type: 'state',
                        common: {
                            name: 'Door open front left open',
                            type: 'boolean',
                            role: 'indicator',
                            read: true,
                            write: false,
                        },
                        native: {},
                    });
            
                    await this.setObjectNotExistsAsync(vin + '.vehicleStatus.doorOpen.frontRight', {
                        type: 'state',
                        common: {
                            name: 'Door open front right open',
                            type: 'boolean',
                            role: 'indicator',
                            read: true,
                            write: false,
                        },
                        native: {},
                    });
            
                    await this.setObjectNotExistsAsync(vin + '.vehicleStatus.doorOpen.backLeft', {
                        type: 'state',
                        common: {
                            name: 'Door open back left open',
                            type: 'boolean',
                            role: 'indicator',
                            read: true,
                            write: false,
                        },
                        native: {},
                    });
            
                    await this.setObjectNotExistsAsync(vin + '.vehicleStatus.doorOpen.backRight', {
                        type: 'state',
                        common: {
                            name: 'Door open back right left open',
                            type: 'boolean',
                            role: 'indicator',
                            read: true,
                            write: false,
                        },
                        native: {},
                    });
            
                    await this.setObjectNotExistsAsync(vin + '.vehicleStatus.airCtrlOn', {
                        type: 'state',
                        common: {
                            name: 'Vehicle air control',
                            type: 'boolean',
                            role: 'indicator',
                            read: true,
                            write: false,
                        },
                        native: {},
                    });
            
                    await this.setObjectNotExistsAsync(vin + '.vehicleStatus.airTemp', {
                        type: 'state',
                        common: {
                            name: 'Vehicle air tempereature',
                            type: 'number',
                            role: 'indicator',
                            read: true,
                            write: false,
                        },
                        native: {},
                    });
            
                    await this.setObjectNotExistsAsync(vin + '.vehicleStatus.smartKeyBatteryWarning', {
                        type: 'state',
                        common: {
                            name: 'Smart key battery Warning',
                            type: 'boolean',
                            role: 'indicator',
                            read: true,
                            write: false,
                        },
                        native: {},
                    });
            
                    await this.setObjectNotExistsAsync(vin + '.vehicleStatus.washerFluidStatus', {
                        type: 'state',
                        common: {
                            name: 'Washer fluid status',
                            type: 'boolean',
                            role: 'indicator',
                            read: true,
                            write: false,
                        },
                        native: {},
                    });
            
                    await this.setObjectNotExistsAsync(vin + '.vehicleStatus.breakOilStatus', {
                        type: 'state',
                        common: {
                            name: 'Breal oil status',
                            type: 'boolean',
                            role: 'indicator',
                            read: true,
                            write: false,
                        },
                        native: {},
                    });
            
                    await this.setObjectNotExistsAsync(vin + '.vehicleStatus.steerWheelHeat', {
                        type: 'state',
                        common: {
                            name: 'Steer wheel heat',
                            type: 'boolean',
                            role: 'indicator',
                            read: true,
                            write: false,
                        },
                        native: {},
                    });
            
                    await this.setObjectNotExistsAsync(vin + '.vehicleStatus.sideBackWindowHeat', {
                        type: 'state',
                        common: {
                            name: 'Side back window heat',
                            type: 'number',
                            role: 'indicator',
                            read: true,
                            write: false,
                        },
                        native: {},
                    });
            
                    await this.setObjectNotExistsAsync(vin + '.vehicleStatus.dte', {
                        type: 'state',
                        common: {
                            name: 'Vehicle total available range',
                            type: 'number',
                            role: 'indicator',
                            read: true,
                            write: false,
                        },
                        native: {},
                    });
            
                    await this.setObjectNotExistsAsync(vin + '.vehicleStatus.evModeRange', {
                        type: 'state',
                        common: {
                            name: 'Vehicle total available range for ev',
                            type: 'number',
                            role: 'indicator',
                            read: true,
                            write: false,
                        },
                        native: {},
                    });
            
                    await this.setObjectNotExistsAsync(vin + '.vehicleStatus.gasModeRange', {
                        type: 'state',
                        common: {
                            name: 'Vehicle total available range for gas',
                            type: 'number',
                            role: 'indicator',
                            read: true,
                            write: false,
                        },
                        native: {},
                    });
            
                    //Charge
                    await this.setObjectNotExistsAsync(vin + '.vehicleStatus.battery.charge_limit_slow', {
                        type: 'state',
                        common: {
                            name: 'Vehicle charge limit for slow charging',
                            type: 'number',
                            role: 'indicator',
                            read: true,
                            write: true,
                        },
                        native: {},
                    });
                    this.subscribeStates(vin + '.vehicleStatus.battery.charge_limit_slow');
            
                    await this.setObjectNotExistsAsync(vin + '.vehicleStatus.battery.charge_limit_fast', {
                        type: 'state',
                        common: {
                            name: 'Vehicle charge limit for fast charging',
                            type: 'number',
                            role: 'indicator',
                            read: true,
                            write: true,
                        },
                        native: {},
                    });
                    this.subscribeStates(vin + '.vehicleStatus.battery.charge_limit_fast');
            
                    await this.setObjectNotExistsAsync(vin + '.vehicleStatus.battery.minutes_to_charged', {
                        type: 'state',
                        common: {
                            name: 'Vehicle minutes to charged',
                            type: 'number',
                            role: 'indicator',
                            read: true,
                            write: true,
                        },
                        native: {},
                    });
            
                    //Battery
                    await this.setObjectNotExistsAsync(vin + '.vehicleStatus.battery.soc', {
                        type: 'state',
                        common: {
                            name: 'Vehicle battery state of charge',
                            type: 'number',
                            role: 'indicator',
                            read: true,
                            write: false,
                        },
                        native: {},
                    });
            
                    await this.setObjectNotExistsAsync(vin + '.vehicleStatus.battery.charge', {
                        type: 'state',
                        common: {
                            name: 'Vehicle charging',
                            type: 'boolean',
                            role: 'indicator',
                            read: true,
                            write: false,
                        },
                        native: {},
                    });
            
                    await this.setObjectNotExistsAsync(vin + '.vehicleStatus.battery.plugin', {
                        type: 'state',
                        common: {
                            name: 'Charger connected (UNPLUGED = 0, FAST = 1, PORTABLE = 2, STATION = 3)',
                            type: 'number',
                            role: 'indicator',
                            read: true,
                            write: false,
                        },
                        native: {},
                    });
            
                    await this.setObjectNotExistsAsync(vin + '.vehicleStatus.battery.soc-12V', {
                        type: 'state',
                        common: {
                            name: 'Vehicle 12v battery state of charge',
                            type: 'number',
                            role: 'indicator',
                            read: true,
                            write: false,
                        },
                        native: {},
                    });
            
                    await this.setObjectNotExistsAsync(vin + '.vehicleStatus.battery.state-12V', {
                        type: 'state',
                        common: {
                            name: 'Vehicle 12v battery State',
                            type: 'number',
                            role: 'indicator',
                            read: true,
                            write: false,
                        },
                        native: {},
                    });
            
                    //Bereich vehicleLocation
                    await this.setObjectNotExistsAsync(vin + '.vehicleLocation.lat', {
                        type: 'state',
                        common: {
                            name: 'Vehicle position latitude',
                            type: 'string',
                            role: 'indicator',
                            read: true,
                            write: false,
                        },
                        native: {},
                    });
            
                    await this.setObjectNotExistsAsync(vin + '.vehicleLocation.lon', {
                        type: 'state',
                        common: {
                            name: 'Vehicle position longitude',
                            type: 'string',
                            role: 'indicator',
                            read: true,
                            write: false,
                        },
                        native: {},
                    });
            
                    await this.setObjectNotExistsAsync(vin + '.vehicleLocation.speed', {
                        type: 'state',
                        common: {
                            name: 'Vehicle speed',
                            type: 'number',
                            role: 'indicator',
                            read: true,
                            write: false,
                        },
                        native: {},
                    });
            
                    //Bereich Odometer
                    await this.setObjectNotExistsAsync(vin + '.odometer.value', {
                        type: 'state',
                        common: {
                            name: 'Odometer value',
                            type: 'number',
                            role: 'indicator',
                            read: true,
                            write: false,
                        },
                        native: {},
                    });
            
                    await this.setObjectNotExistsAsync(vin + '.odometer.unit', {
                        type: 'state',
                        common: {
                            name: 'Odometer unit',
                            type: 'number',
                            role: 'indicator',
                            read: true,
                            write: false,
                        },
                        native: {},
                    });
                }
                async cleanObjects() {
                    const controlState = await this.getObjectAsync('control.charge');
            
                    if (controlState) {
                        await this.delObjectAsync('control', { recursive: true });
                        await this.delObjectAsync('odometer', { recursive: true });
                        await this.delObjectAsync('vehicleLocation', { recursive: true });
                        await this.delObjectAsync('vehicleStatus', { recursive: true });
                    }
                }
            
                getCircularReplacer() {
                    const seen = new WeakSet();
                    return (key, value) => {
                        if (typeof value === 'object' && value !== null) {
                            if (seen.has(value)) {
                                return;
                            }
                            seen.add(value);
                        }
                        return value;
                    };
                }
            
                getCelsiusFromTempcode(tempCode) {
                    // create a range
                    const tempRange = [];
                    //Range for EU
                    for (let i = 14; i <= 30; i += 0.5) {
                        tempRange.push(i);
                    }
            
                    // get the index
                    const tempIndex = parseInt(tempCode, 16);
            
                    // return the relevant celsius temp
                    return tempRange[tempIndex];
                }
            }
            
            if (require.main !== module) {
                // Export the constructor in compact mode
                /**
                 * @param {Partial<utils.AdapterOptions>} [options={}]
                 */
                module.exports = (options) => new Bluelink(options);
            } else {
                // otherwise start the instance directly
                new Bluelink();
            }
            

            Diese Punkte haben sich zum original geändert:

            • es hatte sich ein kleiner Fehler eingeschlichen der den Wert des neuen States "force_update" das @arteck mit der Version 2.2.7 eingeführt hat nicht richtig an "Bluelinky" übergeben hat (hier fehlte ein .val)
            • sowohl die "Full Status" Abrage als auch die "Fallback" Abfrage kann nun mittels des neuen States "force_update" geschaltet werden, so dass man stets wählen kann ob die Daten nur vom Hyundai-Server kommen (false) oder direkt vom Auto (true) geholt werden.
            • Beim Start des Adapters wird die Einstellung des States "force_update" übergangen und die Daten auf jeden Fall vom PKW geholt, so dass die Daten auf jeden Fall top aktuell sind. Danach muss dann jeder über den State "force_update" entscheiden was er will.
            • Der Zeitstempel "lastInfoUpdate" wird nun erst nach einem erfolgreichen Update gesetzt, so dass man hieran sehen kann ob und wann das letzte erfolgreiche Update erfolgt ist.
            • @Michaelnorge den hard-gecodeten Wert für die Batterieüberwachung habe ich von 88 auf 60 geändert. Vielleicht könnte man das ja mal in die Adaptereinstellungen integrieren, so dass man diesen Wert individuell anpassen kann.

            (Ich hatte das hier schon mal geschrieben: Ich kann eigentlich kein Java programmieren. Ich kann zwar ein Script lesen und verstehe auch zum großen Teil was es macht das war's dann aber auch schon. D.h. die Änderungen in meiner "main.js" sind durch probieren, copy-paste und ein weinig nachlesen entstanden. Will heißen, das Script läuft zwar prima, ist aber nicht unbedingt programmiertechnisch perfekt.)

            Ich selbst nutze die Einstellung FALSE beim State "force_update" mit 360 Abfragen pro Tag (also alle 4 min. eine Abfrage). Mehr Abfragen (alle 3 min. oder mehr) führten bei mir zu einer Fehlermeldung des Hyundai-Servers, dass ich zu viele Abfragen pro Tag an den Server stellen würde. Dann ging sogar die App nicht mehr...
            Sobald ich irgendwie registriere, dass mein Auto geladen wird (Ioniq 5) z.B. Rückmeldung bei der Server Abfrage oder Meldung durch meine Wall-Box, schalte ich per Blockly Script den State "force_update" um auf true, so dass die Daten direkt vom PKW geholt werden. Nach Beendigung des Ladevorgangs schalte ich dann wieder zurück auf false. Das funktioniert super und belastet halt die 12V Batterie so gut wie gar nicht mehr.

            arteckA Offline
            arteckA Offline
            arteck
            Developer Most Active
            schrieb am zuletzt editiert von arteck
            #962

            @stefan-cloer danke dir.. ja manchmal ist man blind.. habs auf GIT hochgeladen..

            in Zeile 315 ist auch noch ein Bug bei dir... da hast du wie ich den async übersehen

            und die Zeile 721 brauchst du auch nicht

            this.subscribeStates(vin + '.control.force_update');
            

            auf den wird nicht einzeln reagiert.. sondern der wird nur gelsen

            ich hab direkt auch den batteryControlState12V eingefügt
            22ba9f01-8d96-4ed3-8789-f479f5dcc01b-grafik.png

            ich habe den wert resultierend aus meiner Umfrage dazu auf 65 gesetzt.. so wie es aussieht wird dieser auch standardmässig so eingestellt
            https://github.com/Newan/ioBroker.bluelink

            jeder kann sich den aber setzten wie er mag

            bitte Testen.. wenn OK dann mach ich eine Version

            zigbee hab ich, zwave auch, nuc's genauso und HA auch

            M S 2 Antworten Letzte Antwort
            0
            • arteckA arteck

              @stefan-cloer danke dir.. ja manchmal ist man blind.. habs auf GIT hochgeladen..

              in Zeile 315 ist auch noch ein Bug bei dir... da hast du wie ich den async übersehen

              und die Zeile 721 brauchst du auch nicht

              this.subscribeStates(vin + '.control.force_update');
              

              auf den wird nicht einzeln reagiert.. sondern der wird nur gelsen

              ich hab direkt auch den batteryControlState12V eingefügt
              22ba9f01-8d96-4ed3-8789-f479f5dcc01b-grafik.png

              ich habe den wert resultierend aus meiner Umfrage dazu auf 65 gesetzt.. so wie es aussieht wird dieser auch standardmässig so eingestellt
              https://github.com/Newan/ioBroker.bluelink

              jeder kann sich den aber setzten wie er mag

              bitte Testen.. wenn OK dann mach ich eine Version

              M Offline
              M Offline
              Michaelnorge
              schrieb am zuletzt editiert von
              #963

              @arteck Genial... gleich mal testen! Danke :-))))

              –--------------------------------------------------------------------------------------

              • Smart mit: Rasp 4B / ioBroker / Conbee2 / Trådfri / Xiaomi / HUE / Logitech Harmony / Aqara / Easee Wallbox / Hyundai Ioniq / Alexa / Google Home / Fully Kiosk / VIS
              1 Antwort Letzte Antwort
              0
              • arteckA arteck

                @stefan-cloer danke dir.. ja manchmal ist man blind.. habs auf GIT hochgeladen..

                in Zeile 315 ist auch noch ein Bug bei dir... da hast du wie ich den async übersehen

                und die Zeile 721 brauchst du auch nicht

                this.subscribeStates(vin + '.control.force_update');
                

                auf den wird nicht einzeln reagiert.. sondern der wird nur gelsen

                ich hab direkt auch den batteryControlState12V eingefügt
                22ba9f01-8d96-4ed3-8789-f479f5dcc01b-grafik.png

                ich habe den wert resultierend aus meiner Umfrage dazu auf 65 gesetzt.. so wie es aussieht wird dieser auch standardmässig so eingestellt
                https://github.com/Newan/ioBroker.bluelink

                jeder kann sich den aber setzten wie er mag

                bitte Testen.. wenn OK dann mach ich eine Version

                S Offline
                S Offline
                stefan.cloer
                schrieb am zuletzt editiert von
                #964

                @arteck die Zeile 721 ist aus meiner Sicht sehr wichtig. Wenn ich das force_update State in den Objekten ändere ohne diese Zeile reagiert das Script ohne diese Zeile erst bei dem übernächsten Update auf die Änderung des States. Mit der Zeile 721 aber bereits bei der nächsten.
                Genau das war der Grund warum ich die eingefügt habe.

                1 Antwort Letzte Antwort
                0
                • arteckA Offline
                  arteckA Offline
                  arteck
                  Developer Most Active
                  schrieb am zuletzt editiert von arteck
                  #965

                  @stefan-cloer

                  this.subscribeStates(vin + '.control.force_update');
                  

                  https://github.com/ioBroker/ioBroker.docs/blob/master/docs/en/dev/adapterdev.md

                  dann nach subscribeStates suchen...

                  ein subscribeStates reagiert direkt auf eine Änderung des werten und lösst WAS aus.. was in unserem Fall nicht zutrifft.. du wllst ja nur beim nächsten durchlauf den Wert mitnehmen.. und nicht druaf DIREKT reagieren wenn sich dieser geändert hat

                  zigbee hab ich, zwave auch, nuc's genauso und HA auch

                  ? S G 3 Antworten Letzte Antwort
                  0
                  • arteckA arteck

                    @stefan-cloer

                    this.subscribeStates(vin + '.control.force_update');
                    

                    https://github.com/ioBroker/ioBroker.docs/blob/master/docs/en/dev/adapterdev.md

                    dann nach subscribeStates suchen...

                    ein subscribeStates reagiert direkt auf eine Änderung des werten und lösst WAS aus.. was in unserem Fall nicht zutrifft.. du wllst ja nur beim nächsten durchlauf den Wert mitnehmen.. und nicht druaf DIREKT reagieren wenn sich dieser geändert hat

                    ? Offline
                    ? Offline
                    Ein ehemaliger Benutzer
                    schrieb am zuletzt editiert von
                    #966

                    @arteck hab mal von Git eingespielt, bisher keine Errors / Warnings, daten werden geholt.
                    Danke!

                    T 1 Antwort Letzte Antwort
                    0
                    • ? Ein ehemaliger Benutzer

                      @arteck hab mal von Git eingespielt, bisher keine Errors / Warnings, daten werden geholt.
                      Danke!

                      T Offline
                      T Offline
                      theGrinch
                      schrieb am zuletzt editiert von
                      #967

                      @ilovegym hier auch. Danke @arteck

                      1 Antwort Letzte Antwort
                      0
                      • arteckA arteck

                        @stefan-cloer

                        this.subscribeStates(vin + '.control.force_update');
                        

                        https://github.com/ioBroker/ioBroker.docs/blob/master/docs/en/dev/adapterdev.md

                        dann nach subscribeStates suchen...

                        ein subscribeStates reagiert direkt auf eine Änderung des werten und lösst WAS aus.. was in unserem Fall nicht zutrifft.. du wllst ja nur beim nächsten durchlauf den Wert mitnehmen.. und nicht druaf DIREKT reagieren wenn sich dieser geändert hat

                        S Offline
                        S Offline
                        stefan.cloer
                        schrieb am zuletzt editiert von stefan.cloer
                        #968

                        @arteck Das mag sein. Dafür verstehe ich zu wenig von Java.

                        Allerdings habe ich gerade deine neue Version eingespielt und es passiert nun genau das was ich in meinem Post zuvor beschrieben habe, das Umschalten des Werts "force_update" wird erst beim übernächsten Update akzeptiert.

                        S 1 Antwort Letzte Antwort
                        0
                        • S stefan.cloer

                          @arteck Das mag sein. Dafür verstehe ich zu wenig von Java.

                          Allerdings habe ich gerade deine neue Version eingespielt und es passiert nun genau das was ich in meinem Post zuvor beschrieben habe, das Umschalten des Werts "force_update" wird erst beim übernächsten Update akzeptiert.

                          S Offline
                          S Offline
                          stefan.cloer
                          schrieb am zuletzt editiert von
                          #969

                          69f24cf2-a4bf-4219-b857-494923a2cffb-image.png

                          ? arteckA 2 Antworten Letzte Antwort
                          0
                          • S stefan.cloer

                            69f24cf2-a4bf-4219-b857-494923a2cffb-image.png

                            ? Offline
                            ? Offline
                            Ein ehemaliger Benutzer
                            schrieb am zuletzt editiert von
                            #970

                            @stefan-cloer @arteck

                            richtig, das kann ich hier nachvollziehen, er holt erst beim uebernaechsten Update vom Auto...

                            1 Antwort Letzte Antwort
                            0
                            • arteckA arteck

                              @stefan-cloer

                              this.subscribeStates(vin + '.control.force_update');
                              

                              https://github.com/ioBroker/ioBroker.docs/blob/master/docs/en/dev/adapterdev.md

                              dann nach subscribeStates suchen...

                              ein subscribeStates reagiert direkt auf eine Änderung des werten und lösst WAS aus.. was in unserem Fall nicht zutrifft.. du wllst ja nur beim nächsten durchlauf den Wert mitnehmen.. und nicht druaf DIREKT reagieren wenn sich dieser geändert hat

                              G Offline
                              G Offline
                              GerdSo
                              schrieb am zuletzt editiert von
                              #971

                              @arteck Ich habe gerade die aktuelle Version ebenfalls eingespielt, die Objekte gelöscht und es gibt keine Fehler.
                              Allerdings erwartet er bei mir 3 Variablenformate anders:

                              bluelink.0 2023-03-31 16:58:47.128	info	Read new update for ### directly from the car
                              bluelink.0 2023-03-31 16:54:47.117	info	Update for ### successfull
                              bluelink.0 2023-03-31 16:54:47.111	info	State value to set for "bluelink.0.###.vehicleStatus.steerWheelHeat" has to be type "boolean" but received type "number"
                              bluelink.0 2023-03-31 16:54:47.037	info	State value to set for "bluelink.0.###.vehicleLocation.lon" has to be type "string" but received type "number"
                              bluelink.0 2023-03-31 16:54:46.993	info	State value to set for "bluelink.0.###.vehicleLocation.lat" has to be type "string" but received type "number"
                              bluelink.0 2023-03-31 16:54:19.477	info	Read new update for ### directly from the car
                              bluelink.0 2023-03-31 16:54:19.019	info	1 Vehicles found
                              bluelink.0 2023-03-31 16:54:14.736	info	Login to api
                              bluelink.0 2023-03-31 16:54:14.709	info	starting. Version 2.2.8 (non-npm: Newan/ioBroker.bluelink#dd32222fb61b1af1dde48e9465c3c6d00cc8ac4c) in /opt/iobroker/node_modules/iobroker.bluelink, node: v18.15.0, js-controller: 4.0.24
                              
                              1 Antwort Letzte Antwort
                              0
                              • S stefan.cloer

                                69f24cf2-a4bf-4219-b857-494923a2cffb-image.png

                                arteckA Offline
                                arteckA Offline
                                arteck
                                Developer Most Active
                                schrieb am zuletzt editiert von arteck
                                #972

                                @stefan-cloer ok ok .. ich baus wieder rein.. :-)

                                @GerdSo sollte jetzt auch weg sein... musst aber die 3 (oder wieder alle) per hand löschen damit die neu angelegt werden

                                zigbee hab ich, zwave auch, nuc's genauso und HA auch

                                S G 2 Antworten Letzte Antwort
                                1
                                • arteckA arteck

                                  @stefan-cloer ok ok .. ich baus wieder rein.. :-)

                                  @GerdSo sollte jetzt auch weg sein... musst aber die 3 (oder wieder alle) per hand löschen damit die neu angelegt werden

                                  S Offline
                                  S Offline
                                  stefan.cloer
                                  schrieb am zuletzt editiert von
                                  #973

                                  @arteck prima, aus meiner Sicht arbeitet das Script jetzt (fast) perfekt. Das einzige was aus meiner Sicht noch angepasst werden sollte ist die maximale request Anzahl. Da wir ja jetzt die 12V Batterie bei einem Update vom Server nicht mehr belasten kann der Wert sicherlich von 48 auf 400 erhöht werden.

                                  1 Antwort Letzte Antwort
                                  0
                                  • arteckA arteck

                                    @stefan-cloer ok ok .. ich baus wieder rein.. :-)

                                    @GerdSo sollte jetzt auch weg sein... musst aber die 3 (oder wieder alle) per hand löschen damit die neu angelegt werden

                                    G Offline
                                    G Offline
                                    GerdSo
                                    schrieb am zuletzt editiert von
                                    #974

                                    @arteck Danke, Fehler ist weg, jetzt habe ich das gleiche Problem wie @stefan-cloer
                                    Vorher konnte ich die Aktualisierungsrate auf 360 stellen, jetzt wird auf 48 zurückgesetzt und das sieht man nur im Protokoll, im Einstellungsdialog werden die 360 akzeptiert.

                                    Was mich etwas irritiert ist der Variablentyp von force_update in der Objekt-Ansicht. Das müsste nach meinem Empfinden ein Boolean oder state sein und nicht ein Button. Das war in der "alten" 2.2.8 auch so, siehe Screenshot in Nachricht vom 30.3. 17:55
                                    Bei mir sieht es so aus36b8ec99-cac6-4892-9721-263b6b970a9a-image.png

                                    ? 1 Antwort Letzte Antwort
                                    0
                                    • G GerdSo

                                      @arteck Danke, Fehler ist weg, jetzt habe ich das gleiche Problem wie @stefan-cloer
                                      Vorher konnte ich die Aktualisierungsrate auf 360 stellen, jetzt wird auf 48 zurückgesetzt und das sieht man nur im Protokoll, im Einstellungsdialog werden die 360 akzeptiert.

                                      Was mich etwas irritiert ist der Variablentyp von force_update in der Objekt-Ansicht. Das müsste nach meinem Empfinden ein Boolean oder state sein und nicht ein Button. Das war in der "alten" 2.2.8 auch so, siehe Screenshot in Nachricht vom 30.3. 17:55
                                      Bei mir sieht es so aus36b8ec99-cac6-4892-9721-263b6b970a9a-image.png

                                      ? Offline
                                      ? Offline
                                      Ein ehemaliger Benutzer
                                      schrieb am zuletzt editiert von
                                      #975

                                      @gerdso richtig, jetzt sollte man aus dem Button einen Switch machen, kann man selbst einfach in den Objekten, wird dann aber bei Adapterupdate ueberschrieben, sollte also in der naechsten Version am besten geaendert sein.. :)

                                      Bei mir laeuft die aktuelle Git soweit absolut ohne Warnings, mit den angemerkten Aenderungen steht meiner Meinung nach einem Release dann nichts mehr im Wege.. :)

                                      1 Antwort Letzte Antwort
                                      0
                                      • B Offline
                                        B Offline
                                        bigal
                                        schrieb am zuletzt editiert von
                                        #976

                                        Da ich nun auch bei beiden IONIQ5 mehrfach mit leerer 12V da stand zuletzt über Nacht, habe ich die 2.2.8 installiert.

                                        force_update false sende leider bei V2L Nutzung kein update, da ich die beiden Dicken als kostenlose Hausbatterien nutze wäre das wichtig.

                                        der 12V soc wird aber auch nicht mehr geupdatet... bei beiden... seit einmal 12v leer war stockt es da, auch der Tipp weiter oben mit Adapter ne uinstallieren hilft da nicht mehr, einer der I5 hatte dann mal wieder angefangen den 12Vsoc zu senden aber beim nächsten mal 12V leer saugen hatte er dann auch wieder aufgehört.

                                        ? 1 Antwort Letzte Antwort
                                        0
                                        • B bigal

                                          Da ich nun auch bei beiden IONIQ5 mehrfach mit leerer 12V da stand zuletzt über Nacht, habe ich die 2.2.8 installiert.

                                          force_update false sende leider bei V2L Nutzung kein update, da ich die beiden Dicken als kostenlose Hausbatterien nutze wäre das wichtig.

                                          der 12V soc wird aber auch nicht mehr geupdatet... bei beiden... seit einmal 12v leer war stockt es da, auch der Tipp weiter oben mit Adapter ne uinstallieren hilft da nicht mehr, einer der I5 hatte dann mal wieder angefangen den 12Vsoc zu senden aber beim nächsten mal 12V leer saugen hatte er dann auch wieder aufgehört.

                                          ? Offline
                                          ? Offline
                                          Ein ehemaliger Benutzer
                                          schrieb am zuletzt editiert von
                                          #977

                                          @bigal

                                          Hi, der 12V Wert wird meist nur nach 20min Fahrt aktualisiert, das liegt nicht am Adapter, sondern am System von Hyundai.. so ist es auf jedem Fall bei meinem Ioniq5. Abgesehen davon ist der Wert in % anscheinend sowieso nach dem Wasserdruck in Sued-Korea abhaengig.. und hat weniger mit dem Zustand der 12V Batterie zu tun..

                                          Um eine leere 12V vorzubeugen, empfiehlt es sich einen Batteryguard zu installieren, den du per Bluetooth auslesen kannst.
                                          Oder nimm n ESP32 und n paar Widerstände und lese dir die Werte alle 30min aus und sende es per Wifi an den iobroker..

                                          Ich parke im Hof immer so, dass der Batteryguard in Reichweite von nem Raspi ist, der liest dann die Bluetooth mit dem Gatttool aus und sendet es per curl an den iobroker-simple-Api Adapter. Dann werte ich das grafisch mit Flot aus, und kann es mir in MinuVIS ansehen..

                                          B 2 Antworten Letzte Antwort
                                          0
                                          Antworten
                                          • In einem neuen Thema antworten
                                          Anmelden zum Antworten
                                          • Älteste zuerst
                                          • Neuste zuerst
                                          • Meiste Stimmen


                                          Support us

                                          ioBroker
                                          Community Adapters
                                          Donate

                                          709

                                          Online

                                          32.4k

                                          Benutzer

                                          81.5k

                                          Themen

                                          1.3m

                                          Beiträge
                                          Community
                                          Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen | Einwilligungseinstellungen
                                          ioBroker Community 2014-2025
                                          logo
                                          • Anmelden

                                          • Du hast noch kein Konto? Registrieren

                                          • Anmelden oder registrieren, um zu suchen
                                          • Erster Beitrag
                                            Letzter Beitrag
                                          0
                                          • Home
                                          • Aktuell
                                          • Tags
                                          • Ungelesen 0
                                          • Kategorien
                                          • Unreplied
                                          • Beliebt
                                          • GitHub
                                          • Docu
                                          • Hilfe