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. Huawei Wallbox - S Charger (7kw/h / 22kw/h) Adapter test

NEWS

  • Neuer Blogbeitrag: Monatsrückblick - Dezember 2025 🎄
    BluefoxB
    Bluefox
    11
    1
    524

  • Weihnachtsangebot 2025! 🎄
    BluefoxB
    Bluefox
    24
    1
    1.7k

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

Huawei Wallbox - S Charger (7kw/h / 22kw/h) Adapter test

Geplant Angeheftet Gesperrt Verschoben Tester
25 Beiträge 8 Kommentatoren 4.7k Aufrufe 7 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.
  • stolly82S stolly82

    Hier schon mal vorab das Javascript, das könnt Ihr zum testen so übernehmen!

    Einfach oben die Zugangsdaten aus der mobilen App eingeben und fertig.
    @baerengraben @Fabio

    const axios = require('axios');
    
    // Konfiguration
    const CONFIG = {
        userName: 'MySUERNAME',
        password: 'MyPASSWORD',
        grantType: 'password',
        appClientId: '86366133-B8B5-41FA-8EB9-E5A64229E3E1',
        httpsAgent: new (require('https').Agent)({ rejectUnauthorized: false }),
        interval: 1200000 // Intervall in Millisekunden für wiederkehrende Abfragen
    };
    
    // Beschreibbare IDs (manuell festgelegt)
    const WRITABLE_IDS = [
        20001, 20002, 20004, 20005, 20006, 20010, 20011, 20013, 20015, 20016, 20017, 538976529, 538976290, 538976533, 538976534, 538976570, 538976800
    ];
    
    
    let authData = null;
    
    // Authentifizierung und Planung der Token-Erneuerung
    async function authenticateAndScheduleRenewal() {
        authData = await authenticate();
        if (!authData) {
            log('Authentifizierung fehlgeschlagen', 'error');
            return;
        }
    
        const refreshTime = (authData.expires - 300) * 1000; // Erneuerung 5 Minuten vor Ablauf
        log(`Nächste Token-Erneuerung in ${(refreshTime / 1000 / 60).toFixed(2)} Minuten`, 'info');
    
        setTimeout(authenticateAndScheduleRenewal, refreshTime);
    }
    
    // Authentifizierung
    async function authenticate() {
        try {
            const response = await axios.post(
                "https://intl.fusionsolar.huawei.com:32800/rest/neteco/appauthen/v1/smapp/app/token",
                JSON.stringify({
                    userName: CONFIG.userName,
                    value: CONFIG.password,
                    grantType: CONFIG.grantType,
                    verifyCode: "",
                    appClientId: CONFIG.appClientId
                }),
                {
                    headers: {
                        "Content-Type": "application/json"
                    },
                    httpsAgent: CONFIG.httpsAgent
                }
            );
    
            if (response.data && response.data.data && response.data.data.accessToken) {
                log("Benutzer validiert. Antwort: " + JSON.stringify(response.data), 'info');
                setState('huawei-smart-charger.info.connection', true, true);
                response.data.data.expiryTime = new Date().getTime() + (response.data.data.expires * 1000);
                return response.data.data;
            } else {
                log("Fehler bei der Authentifizierung: Ungültige Antwort. Antwort: " + JSON.stringify(response.data), 'error');
                setState('huawei-smart-charger.info.connection', false, true);
                return null;
            }
        } catch (error) {
            log("Fehler bei der Authentifizierung: " + error.message, 'error');
            setState('huawei-smart-charger.info.connection', false, true);
            return null;
        }
    }
    
    // Benutzerinformationen abrufen
    async function getUserDetailInfo() {
        try {
            const response = await axios.get(
                "https://" + authData.regionFloatIp + ':32800/rest/neteco/phoneapp/v1/datacenter/getuserdetailinfo',
                {
                    headers: {
                        'roaRand': authData.roaRand,
                        'Cookie': 'locale=de-de;bspsession=' + authData.accessToken + ';dp-session=' + authData.accessToken + '; Secure; HttpOnly'
                    },
                    httpsAgent: CONFIG.httpsAgent
                }
            );
            log("Benutzerinformationen: " + JSON.stringify(response.data), 'info');
            const userInfo = response.data;
            await createAndSetObjects('huawei-smart-charger.User', userInfo);
        } catch (error) {
            log("Fehler beim Abrufen der Benutzerinformationen: " + error.message, 'error');
        }
    }
    
    // Serverinformationen abrufen
    async function getServerInfo() {
        try {
            const response = await axios.get(
                "https://" + authData.regionFloatIp + ":32800/rest/neteco/phoneapp/v2/fusionsolarbusiness/company/getorganizationcompanybyuser",
                {
                    headers: {
                        'roaRand': authData.roaRand,
                        'Cookie': 'locale=de-de;bspsession=' + authData.accessToken + ';dp-session=' + authData.accessToken + '; Secure; HttpOnly'
                    },
                    httpsAgent: CONFIG.httpsAgent
                }
            );
            log("Serverinformationen: " + JSON.stringify(response.data), 'info');
            const serverInfo = response.data.data;
            await createAndSetObjects('huawei-smart-charger.Server', serverInfo);
        } catch (error) {
            log("Fehler beim Abrufen der Serverinformationen: " + error.message, 'error');
        }
    }
    
    // Station-Liste abrufen
    async function getStationList() {
        try {
            const response = await axios.post(
                "https://" + authData.regionFloatIp + ":32800/rest/pvms/web/station/v1/station/station-list",
                {
                    "locale": "de_DE",
                    "sortId": "createTime",
                    "timeZone": "2.00",
                    "pageSize": "11",
                    "supportMDevice": "1",
                    "sortDir": "DESC",
                    "curPage": 1
                },
                {
                    headers: {
                        'roaRand': authData.roaRand,
                        'Cookie': 'locale=de-de;bspsession=' + authData.accessToken + ';dp-session=' + authData.accessToken + '; Secure; HttpOnly',
                        "Content-Type": "application/json"
                    },
                    httpsAgent: CONFIG.httpsAgent
                }
            );
            log("Station-Liste: " + JSON.stringify(response.data), 'info');
            const stationList = response.data.data.list[0];
            await createAndSetObjects('huawei-smart-charger.Station', stationList);
        } catch (error) {
            log("Fehler beim Abrufen der Station-Liste: " + error.message, 'error');
        }
    }
    
    // Wallbox-Informationen abrufen
    async function getWallboxInfo() {
        try {
            const parentDn = getState('huawei-smart-charger.Station.dn').val;
            if (!parentDn) {
                await getUserDetailInfo();
                await getServerInfo();
                await getStationList();
                return await getWallboxInfo();
            }
    
            const response = await axios.post(
                "https://" + authData.regionFloatIp + `:32800/rest/neteco/web/config/device/v1/device-list`,
                "conditionParams.curPage=0&conditionParams.mocTypes=60080&conditionParams.parentDn=" + parentDn + "&conditionParams.recordperpage=500",
                {
                    headers: {
                        'roaRand': authData.roaRand,
                        'Cookie': 'locale=de-de;bspsession=' + authData.accessToken + ';dp-session=' + authData.accessToken + '; Secure; HttpOnly',
                        "Content-Type": "application/x-www-form-urlencoded"
                    },
                    httpsAgent: CONFIG.httpsAgent
                }
            );
    
            log("Wallbox-Informationen: " + JSON.stringify(response.data), 'debug');
            const wallboxInfo = response.data.data[0];
    
            // Erstelle den Basisordner für die Wallbox-Informationen
            const basePath = `huawei-smart-charger.WallboxInfo`;
    
            // Speichere alle Daten in IoBroker, einschließlich paramValues
            for (const key in wallboxInfo) {
                if (key === 'paramValues') {
                    // Speziell für paramValues
                    const paramValuesPath = `${basePath}.paramValues`;
                    for (const paramKey in wallboxInfo.paramValues) {
                        const paramValue = wallboxInfo.paramValues[paramKey];
                        await setObject(`${paramValuesPath}.${paramKey}`, {
                            type: 'state',
                            common: {
                                name: `Parameter ${paramKey}`,
                                type: typeof paramValue,
                                role: 'info',
                                read: true,
                                write: WRITABLE_IDS.includes(parseInt(paramKey)) // Schreibbare IDs berücksichtigen
                            },
                            native: { id: paramKey, value: paramValue }
                        });
                        await setState(`${paramValuesPath}.${paramKey}`, paramValue, true);
                    }
                } else {
                    // Speichere alle anderen Daten in IoBroker
                    await setObject(`${basePath}.${key}`, {
                        type: 'state',
                        common: {
                            name: key,
                            type: typeof wallboxInfo[key],
                            role: 'info',
                            read: true,
                            write: false
                        },
                        native: { value: wallboxInfo[key] }
                    });
                    await setState(`${basePath}.${key}`, wallboxInfo[key], true);
                }
            }
    
            // Speichere die dnId explizit im Basisordner
            const dnId = wallboxInfo.dnId;
            await setState(`${basePath}.dnId`, dnId, true);
    
            // Rufe die Wallbox-Konfigurationsinformationen auf, wenn paramValues vorhanden sind
            if (wallboxInfo.paramValues) {
                await getWallboxConfigInfo(dnId, wallboxInfo.paramValues);
            }
        } catch (error) {
            log("Fehler beim Abrufen der Wallbox-Informationen: " + error.message, 'error');
        }
    }
    
    
    
    on({ id: new RegExp('^huawei-smart-charger\\.Wallbox\\.Settings\\.[^.]+$'), change: 'ne' }, async (obj) => {
        if (obj.state.ack) {
            return; // Wenn die Änderung von der API bestätigt wurde, ignoriere sie
        }
    
        const writableId = obj.native?.id;
        if (!writableId || !WRITABLE_IDS.includes(writableId)) {
            log(`Keine beschreibbare ID für ${obj.id} gefunden.`, 'warn');
            return;
        }
    
        try {
            // Verwende die gespeicherte dnId aus dem Objekt
            const dnId = getState(`${obj.id.replace('.Settings.', '.Settings.dnId')}`).val;
            if (!authData || (authData && new Date().getTime() > authData.expiryTime)) {
                await authenticateAndScheduleRenewal();
            }
    
            if (authData && dnId) {
                const requestData = {
                    changeValues: [{ id: writableId, value: obj.state.val }],
                    dnId: dnId
                };
    
                log(`Sende Anfrage mit Daten: ${JSON.stringify(requestData)}`, 'debug');
    
                const response = await axios.post(
                    "https://" + authData.regionFloatIp + ":32800/rest/neteco/web/homemgr/v1/device/set-config-info",
                    JSON.stringify(requestData),
                    {
                        headers: {
                            'roaRand': authData.roaRand,
                            'Cookie': `locale=de-de;bspsession=${authData.accessToken};dp-session=${authData.accessToken}; Secure; HttpOnly`,
                            'Content-Type': 'application/json',
                            'x-timezone-offset': '120',
                            'client-info': '_manufacturer=iPhone;_model=iPhone;_os_ver=18.0.1;_os=iOS;_app_ver=24.6.102006;_package_name=com.huawei.smartpvms;appClientId=86366133-B8B5-41FA-8EB9-E5A64229E3D5',
                            'x-requested-with': 'XMLHttpRequest',
                            'User-Agent': 'iCleanPower/24.6.102006 (iPhone; iOS 18.0.1; Scale/3.00)',
                            'Accept-Language': 'de-DE;q=1, en-DE;q=0.9, zh-Hans-DE;q=0.8',
                            'Accept': '*/*'
                        },
                        httpsAgent: CONFIG.httpsAgent
                    }
                );
    
                log(`Antwort vom Server: ${JSON.stringify(response.data)}`, 'info');
                if (response.data && response.data.code === 0) {
                    await setState(obj.id, obj.state.val, true);
                }
            }
        } catch (error) {
            log(`Fehler beim Ändern des Werts für ${obj.id}: ${error.message}`, 'error');
            if (error.response) {
                log(`Fehlerantwort vom Server: ${JSON.stringify(error.response.data)}`, 'error');
            }
        }
    });
    // Wallbox-Einstellungen abrufen und Konfigurationsinformationen anfordern
    async function getWallboxSettings() {
        const parentDn = getState('huawei-smart-charger.WallboxInfo.dn').val;
        try {
            if (!parentDn) {
                await getWallboxInfo();
                return await getWallboxSettings();
            }
    
            const response = await axios.get(
                "https://" + authData.regionFloatIp + `:32800/rest/neteco/web/config/device/v1/children-list?conditionParams.curPage=0&conditionParams.mocTypes=60081&conditionParams.parentDn=${encodeURIComponent(parentDn)}&conditionParams.recordperpage=1`,
                {
                    headers: {
                        'roaRand': authData.roaRand,
                        'Cookie': 'locale=de-de;bspsession=' + authData.accessToken + ';dp-session=' + authData.accessToken + '; Secure; HttpOnly'
                    },
                    httpsAgent: CONFIG.httpsAgent
                }
            );
    
            log(`Wallbox-Einstellungen für ${parentDn}: ` + JSON.stringify(response.data), 'info');
            const wallboxSettings = response.data.data[0];
    
            // Speichern der dnId
            const dnId = wallboxSettings.dnId;
            //setState('huawei-smart-charger.WallboxSettings.dnId', dnId, true);
    
            // Erstelle die Struktur für paramValues und andere Daten
            const basePath = `huawei-smart-charger.WallboxSettings.${dnId}`;
    
            // Speichere alle Schlüssel von wallboxSettings in IoBroker, einschließlich paramValues
            for (const key in wallboxSettings) {
                if (key === 'paramValues') {
                    // Speziell für paramValues
                    const paramValuesPath = `${basePath}.paramValues`;
                    for (const paramKey in wallboxSettings.paramValues) {
                        const paramValue = wallboxSettings.paramValues[paramKey];
                        await setObject(`${paramValuesPath}.${paramKey}`, {
                            type: 'state',
                            common: {
                                name: `Parameter ${paramKey}`,
                                type: typeof paramValue,
                                role: 'info',
                                read: true,
                                write: WRITABLE_IDS.includes(parseInt(paramKey)) // Schreibbare IDs berücksichtigen
                            },
                            native: { id: paramKey, value: paramValue }
                        });
                        await setState(`${paramValuesPath}.${paramKey}`, paramValue, true);
                    }
                } else {
                    // Speichere alle anderen Daten in IoBroker
                    await setObject(`${basePath}.${key}`, {
                        type: 'state',
                        common: {
                            name: key,
                            type: typeof wallboxSettings[key],
                            role: 'info',
                            read: true,
                            write: false
                        },
                        native: { value: wallboxSettings[key] }
                    });
                    await setState(`${basePath}.${key}`, wallboxSettings[key], true);
                }
            }
    
            // Nur beim ersten Mal die Wallbox-Konfigurationsinformationen abrufen
            if (!getWallboxConfigInfo.calledWallboxSettings) {
                await getWallboxConfigInfo(dnId, wallboxSettings.paramValues);
                getWallboxConfigInfo.calledWallboxSettings = true;
            }
        } catch (error) {
            log(`Fehler beim Abrufen der Wallbox-Einstellungen für ${parentDn}: ${error.message}`, 'info');
        }
    }
    
    // Wallbox-Konfigurationsinformationen abrufen und in den entsprechenden Pfaden anlegen
    async function getWallboxConfigInfo(dnId, paramValues) {
        if (!paramValues) {
            log(`Keine Parameterwerte für dnId ${dnId} gefunden.`, 'info');
            return;
        }
    
        for (const id of Object.keys(paramValues)) {
            try {
                const conditions = [{ queryAll: 0, signals: [id], dnId }];
                const response = await axios.post(
                    "https://" + authData.regionFloatIp + ":32800/rest/neteco/web/homemgr/v1/device/get-config-info",
                    JSON.stringify({ conditions }),
                    {
                        headers: {
                            'roaRand': authData.roaRand,
                            'Cookie': `locale=de-de;bspsession=${authData.accessToken};dp-session=${authData.accessToken}; Secure; HttpOnly`,
                            "Content-Type": "application/json"
                        },
                        httpsAgent: CONFIG.httpsAgent
                    }
                );
    
                log(`Wallbox-Konfigurationsinformationen für ${dnId}, Signal ${id}: ` + JSON.stringify(response.data), 'debug');
                const wallboxConfigInfo = response.data;
                if (wallboxConfigInfo && wallboxConfigInfo[dnId] && wallboxConfigInfo[dnId][0]) {
                    const { name, realValue, value, enumMap, unit } = wallboxConfigInfo[dnId][0];
                    if (!name) continue;
    
                    // Sanitize the object ID, but not the display name
                    const sanitizedKey = name
                        .replace(/ä/g, 'ae')
                        .replace(/ö/g, 'oe')
                        .replace(/ü/g, 'ue')
                        .replace(/Ä/g, 'Ae')
                        .replace(/Ö/g, 'Oe')
                        .replace(/Ü/g, 'Ue')
                        .replace(/ß/g, 'ss')
                        .replace(/\s+/g, '_')
                        .replace(/[^\w\d_]/g, '');
    
    
                    // Speichere in huawei-smart-charger.Wallbox.Values
                    const key = sanitizedKey;
                    const stateValue = enumMap && Object.keys(enumMap).length > 0 ? value : realValue;
                    const valuePath = `huawei-smart-charger.Wallbox.Values.${key}`;
                    const settingsPath = `huawei-smart-charger.Wallbox.Settings.${key}`;
    
                    // Objekt in Values erstellen
                    await setObject(valuePath, {
                        type: 'state',
                        common: {
                            name: name, // Keep the original name here
                            type: typeof stateValue,
                            role: 'info',
                            read: true,
                            write: WRITABLE_IDS.includes(parseInt(id)),
                            unit: unit || undefined,
                            states: Object.keys(enumMap).length > 0 ? enumMap : undefined,
                            dnId: dnId // Speichern der dnId in common
                        },
                        native: wallboxConfigInfo[dnId][0]
                    });
                    await setState(valuePath, stateValue, true);
    
                    // Wenn das Objekt schreibbar ist, auch in Settings erstellen
                    if (WRITABLE_IDS.includes(parseInt(id))) {
                        await setObject(settingsPath, {
                            type: 'state',
                            common: {
                                name: name, // Keep the original name here
                                type: typeof stateValue,
                                role: 'info',
                                read: true,
                                write: true,
                                unit: unit || undefined,
                                states: Object.keys(enumMap).length > 0 ? enumMap : undefined,
                                dnId: dnId // Speichern der dnId in common
                            },
                            native: wallboxConfigInfo[dnId][0]
                        });
                        await setState(settingsPath, stateValue, true);
                    }
                }
            } catch (error) {
                log(`Fehler beim Abrufen der Wallbox-Konfigurationsinformationen für ${dnId}, Signal ${id}: ${error.message}`, 'error');
            }
        }
    }
    
    
    async function createAndSetObjects(basePath, data) {
        if (!data) {
            log(`Daten für ${basePath} sind null oder undefined.`, 'error');
            return;
        }
    
        for (const key in data) {
            if (data.hasOwnProperty(key)) {
                const value = data[key];
                // Ersetze Leerzeichen im Objektnamen durch '_'
                const sanitizedKey = key.replace(/\s+/g, '_');
                const id = `${basePath}.${sanitizedKey}`;
                const objType = typeof value === 'object' && value !== null ? 'channel' : 'state';
    
                log(`Versuche, Objekt ${id} zu erstellen. Typ: ${objType}, Wert: ${JSON.stringify(value)}`, 'info');
    
                await setObject(id, {
                    type: objType,
                    common: {
                        name: sanitizedKey,
                        type: typeof value,
                        role: objType === 'channel' ? 'folder' : 'state',
                        read: true,
                        write: WRITABLE_IDS.includes(parseInt(key))
                    },
                    native: typeof value === 'object' && value !== null ? value : { value: value }
                });
    
                if (objType === 'state' && value !== null && value !== undefined) {
                    await setState(id, value, true);
                } else if (objType === 'channel' && value !== null) {
                    // Rekursiv verschachtelte Objekte verarbeiten
                    await createAndSetObjects(id, value);
                }
            }
        }
    }
    
    
    // Aktualisierung des Verbindungsstatus
    function updateConnectionState(isConnected) {
        try {
            setState('huawei-smart-charger.info.connection', isConnected, true);
        } catch (error) {
            log(`Fehler beim Aktualisieren des Verbindungsstatus: ${error.message}`, 'error');
        }
    }
    
    // Hauptlogik zur Authentifizierung und Datenabfrage
    async function main() {
        await authenticateAndScheduleRenewal();
        if (!authData) return;
    
        await getUserDetailInfo();
        await getServerInfo();
        await getStationList();
        await getWallboxInfo();
        await getWallboxSettings();
        await getChargeStatus();
        
    }
    
    // Lausche auf Änderungen der Settings und sende PUT-Anfrage an die API
    on({ id: new RegExp('^huawei-smart-charger\\.Wallbox\\.Settings\\.[^.]+$'), change: 'ne' }, async (obj) => {
        if (obj.state.ack) {
            return; // Wenn die Änderung von der API bestätigt wurde, ignoriere sie
        }
    
        const writableId = obj.native?.id;
        if (!writableId || !WRITABLE_IDS.includes(writableId)) {
            log(`Keine beschreibbare ID für ${obj.id} gefunden.`, 'warn');
            return;
        }
    
        try {
            // Lese die dnId aus dem Objekt in common
            const dnId = getObject(obj.id).common.dnId;
            if (!authData || (authData && new Date().getTime() > authData.expiryTime)) {
                await authenticateAndScheduleRenewal();
            }
    
            if (authData && dnId) {
                const requestData = {
                    changeValues: [{ id: writableId, value: obj.state.val }],
                    dnId: dnId
                };
    
                log(`Sende Anfrage mit Daten: ${JSON.stringify(requestData)}`, 'debug');
    
                const response = await axios.post(
                    "https://" + authData.regionFloatIp + ":32800/rest/neteco/web/homemgr/v1/device/set-config-info",
                    JSON.stringify(requestData),
                    {
                        headers: {
                            'roaRand': authData.roaRand,
                            'Cookie': `locale=de-de;bspsession=${authData.accessToken};dp-session=${authData.accessToken}; Secure; HttpOnly`,
                            'Content-Type': 'application/json',
                            'x-timezone-offset': '120',
                            'client-info': '_manufacturer=iPhone;_model=iPhone;_os_ver=18.0.1;_os=iOS;_app_ver=24.6.102006;_package_name=com.huawei.smartpvms;appClientId=86366133-B8B5-41FA-8EB9-E5A64229E3D5',
                            'x-requested-with': 'XMLHttpRequest',
                            'User-Agent': 'iCleanPower/24.6.102006 (iPhone; iOS 18.0.1; Scale/3.00)',
                            'Accept-Language': 'de-DE;q=1, en-DE;q=0.9, zh-Hans-DE;q=0.8',
                            'Accept': '*/*'
                        },
                        httpsAgent: CONFIG.httpsAgent
                    }
                );
    
                log(`Antwort vom Server: ${JSON.stringify(response.data)}`, 'debug');
                if (response.data) {
                    await setState(obj.id, obj.state.val, true);
                }
                await getWallboxInfo();
                await getWallboxSettings();
            }
        } catch (error) {
            log(`Fehler beim Ändern des Werts für ${obj.id}: ${error.message}`, 'error');
            if (error.response) {
                log(`Fehlerantwort vom Server: ${JSON.stringify(error.response.data)}`, 'error');
            }
        }
    });
    
    // Monitor changes in WallboxSettings and WallboxInfo under paramValues
    on({ id: new RegExp('^huawei-smart-charger\\.Wallbox(Settings|Info)\\.[^.]+\\.paramValues\\.[^.]+$'), change: 'ne' }, async (obj) => {
        if (obj.state.ack) {
            return; // If the change was confirmed by the API, ignore it
        }
    
        try {
            // Extract the parameter ID from the changed paramValues instance
            const paramId = parseInt(obj.id.split('.').pop()); // Extract the parameter ID from the object path
    
            // Define a helper function to update corresponding objects
            const updateObjects = async (basePath) => {
                getObjectView('system', 'state', { startkey: basePath, endkey: basePath + "\u9999" }, async (err, allObjects) => {
                    if (err) {
                        log(`Error fetching objects from ${basePath}: ${err.message}`, 'error');
                        return;
                    }
    
                    for (const obj of allObjects.rows) {
                        const nativeId = obj.value.native?.id;
                        if (nativeId === paramId) {
                            // Update the state in the corresponding object
                            const newValue = obj.state.val;
                            await setState(obj.id, newValue, true);
                            log(`Updated value in ${obj.id} to: ${newValue}`, 'info');
                        }
                    }
                });
            };
    
            // Update the corresponding objects in Wallbox.Values and Wallbox.Settings
            await updateObjects('huawei-smart-charger.Wallbox.Values.');
            await updateObjects('huawei-smart-charger.Wallbox.Settings.');
    
        } catch (error) {
            log(`Error while updating Wallbox.Values or Wallbox.Settings from paramValues change: ${error.message}`, 'error');
        }
    });
    
    // Ladestatus abfragen
    async function getChargeStatus() {
        try {
            // Fetch the dnId from the IoBroker state
            const dnId = getState('huawei-smart-charger.WallboxInfo.dnId').val;
            if (!dnId) {
                log('dnId not found for getChargeStatus', 'warn');
                return;
            }
    
            // Construct the request payload based on the provided curl example
            const requestData = {
                gunNumber: 1, // Fixed value as per the example
                needRealTimeStatus: false, // This will be toggled based on the interval logic
                dnId: dnId
            };
    
            // Perform the POST request
            const response = await axios.post(
                "https://" + authData.regionFloatIp + ":32800/rest/neteco/web/homemgr/v1/charger/status/charge-status",
                JSON.stringify(requestData),
                {
                    headers: {
                        'roaRand': authData.roaRand,
                        'Cookie': `locale=de-de;bspsession=${authData.accessToken};dp-session=${authData.accessToken}; Secure; HttpOnly`,
                        'Content-Type': 'application/json',
                        'x-timezone-offset': '120',
                        'client-info': '_manufacturer=iPhone;_model=iPhone;_os_ver=18.0.1;_os=iOS;_app_ver=24.6.102006;_package_name=com.huawei.smartpvms;appClientId=86366133-B8B5-41FA-8EB9-E5A64229E3D5',
                        'x-requested-with': 'XMLHttpRequest',
                        'User-Agent': 'iCleanPower/24.6.102006 (iPhone; iOS 18.0.1; Scale/3.00)',
                        'Accept-Language': 'de-DE;q=1, en-DE;q=0.9, zh-Hans-DE;q=0.8',
                        'Accept': '*/*'
                    },
                    httpsAgent: CONFIG.httpsAgent
                }
            );
    
            // Log the charge status response for testing
            log(`Charge Status response: ${JSON.stringify(response.data)}`, 'info');
    
            // Update interval based on the charge status
            if (response.data && response.data.chargeStatus !== undefined) {
                const status = response.data.chargeStatus;
                log(`Current charge status: ${status}`, 'info');
                scheduleIntervals(status); // Update intervals based on the charge status
            } else {
                log(`Invalid response from getChargeStatus: ${JSON.stringify(response.data)}`, 'warn');
            }
    
        } catch (error) {
            log(`Fehler beim Abrufen des Ladestatus: ${error.message}`, 'error');
            if (error.response) {
                log(`Fehlerantwort vom Server: ${JSON.stringify(error.response.data)}`, 'error');
            }
        }
    }
    
    // Schedule intervals based on the charge status
    function scheduleIntervals(chargeStatus) {
        let intervalTime = 300000; // Default interval: 5 minutes
        let needRealTimeStatus = false;
    
        // Define specific interval times based on the charge status
        if ([3, 4, 7, 8].includes(chargeStatus)) {
            intervalTime = 60000; // 30 seconds for these statuses
            needRealTimeStatus = true; // Enable real-time status when charging or in related states
        } else if ([1, 2, 6, 10, 11].includes(chargeStatus)) {
            intervalTime = 180000; // 3 minutes for these statuses
        }
    
        // Clear any existing intervals
        clearInterval(infoInterval);
        clearInterval(settingsInterval);
    
        // Schedule intervals with the appropriate time
        infoInterval = setInterval(async () => {
            await getWallboxInfo(needRealTimeStatus); // Fetch wallbox info at the set interval
        }, intervalTime);
    
        settingsInterval = setInterval(async () => {
            await getWallboxSettings(needRealTimeStatus); // Fetch wallbox settings at the set interval
        }, intervalTime);
    
        log(`Scheduled intervals: ${intervalTime / 1000} seconds`, 'info');
    }
    
    
    // Initial call to getChargeStatus and start checking intervals
    let infoInterval, settingsInterval;
    async function checkChargeInterval() {
        await getChargeStatus(); // Check the charge status initially and set intervals
        setInterval(async () => {
            await getChargeStatus(); // Re-check the charge status at regular intervals
        }, CONFIG.interval);
    }
    
    
    
    main();
    
    
    B Offline
    B Offline
    baerengraben
    schrieb am zuletzt editiert von
    #13

    @stolly82 Danke! Ich werde mir den Code anschauen und testen :+1:

    1 Antwort Letzte Antwort
    0
    • stolly82S stolly82

      Hier schon mal vorab das Javascript, das könnt Ihr zum testen so übernehmen!

      Einfach oben die Zugangsdaten aus der mobilen App eingeben und fertig.
      @baerengraben @Fabio

      const axios = require('axios');
      
      // Konfiguration
      const CONFIG = {
          userName: 'MySUERNAME',
          password: 'MyPASSWORD',
          grantType: 'password',
          appClientId: '86366133-B8B5-41FA-8EB9-E5A64229E3E1',
          httpsAgent: new (require('https').Agent)({ rejectUnauthorized: false }),
          interval: 1200000 // Intervall in Millisekunden für wiederkehrende Abfragen
      };
      
      // Beschreibbare IDs (manuell festgelegt)
      const WRITABLE_IDS = [
          20001, 20002, 20004, 20005, 20006, 20010, 20011, 20013, 20015, 20016, 20017, 538976529, 538976290, 538976533, 538976534, 538976570, 538976800
      ];
      
      
      let authData = null;
      
      // Authentifizierung und Planung der Token-Erneuerung
      async function authenticateAndScheduleRenewal() {
          authData = await authenticate();
          if (!authData) {
              log('Authentifizierung fehlgeschlagen', 'error');
              return;
          }
      
          const refreshTime = (authData.expires - 300) * 1000; // Erneuerung 5 Minuten vor Ablauf
          log(`Nächste Token-Erneuerung in ${(refreshTime / 1000 / 60).toFixed(2)} Minuten`, 'info');
      
          setTimeout(authenticateAndScheduleRenewal, refreshTime);
      }
      
      // Authentifizierung
      async function authenticate() {
          try {
              const response = await axios.post(
                  "https://intl.fusionsolar.huawei.com:32800/rest/neteco/appauthen/v1/smapp/app/token",
                  JSON.stringify({
                      userName: CONFIG.userName,
                      value: CONFIG.password,
                      grantType: CONFIG.grantType,
                      verifyCode: "",
                      appClientId: CONFIG.appClientId
                  }),
                  {
                      headers: {
                          "Content-Type": "application/json"
                      },
                      httpsAgent: CONFIG.httpsAgent
                  }
              );
      
              if (response.data && response.data.data && response.data.data.accessToken) {
                  log("Benutzer validiert. Antwort: " + JSON.stringify(response.data), 'info');
                  setState('huawei-smart-charger.info.connection', true, true);
                  response.data.data.expiryTime = new Date().getTime() + (response.data.data.expires * 1000);
                  return response.data.data;
              } else {
                  log("Fehler bei der Authentifizierung: Ungültige Antwort. Antwort: " + JSON.stringify(response.data), 'error');
                  setState('huawei-smart-charger.info.connection', false, true);
                  return null;
              }
          } catch (error) {
              log("Fehler bei der Authentifizierung: " + error.message, 'error');
              setState('huawei-smart-charger.info.connection', false, true);
              return null;
          }
      }
      
      // Benutzerinformationen abrufen
      async function getUserDetailInfo() {
          try {
              const response = await axios.get(
                  "https://" + authData.regionFloatIp + ':32800/rest/neteco/phoneapp/v1/datacenter/getuserdetailinfo',
                  {
                      headers: {
                          'roaRand': authData.roaRand,
                          'Cookie': 'locale=de-de;bspsession=' + authData.accessToken + ';dp-session=' + authData.accessToken + '; Secure; HttpOnly'
                      },
                      httpsAgent: CONFIG.httpsAgent
                  }
              );
              log("Benutzerinformationen: " + JSON.stringify(response.data), 'info');
              const userInfo = response.data;
              await createAndSetObjects('huawei-smart-charger.User', userInfo);
          } catch (error) {
              log("Fehler beim Abrufen der Benutzerinformationen: " + error.message, 'error');
          }
      }
      
      // Serverinformationen abrufen
      async function getServerInfo() {
          try {
              const response = await axios.get(
                  "https://" + authData.regionFloatIp + ":32800/rest/neteco/phoneapp/v2/fusionsolarbusiness/company/getorganizationcompanybyuser",
                  {
                      headers: {
                          'roaRand': authData.roaRand,
                          'Cookie': 'locale=de-de;bspsession=' + authData.accessToken + ';dp-session=' + authData.accessToken + '; Secure; HttpOnly'
                      },
                      httpsAgent: CONFIG.httpsAgent
                  }
              );
              log("Serverinformationen: " + JSON.stringify(response.data), 'info');
              const serverInfo = response.data.data;
              await createAndSetObjects('huawei-smart-charger.Server', serverInfo);
          } catch (error) {
              log("Fehler beim Abrufen der Serverinformationen: " + error.message, 'error');
          }
      }
      
      // Station-Liste abrufen
      async function getStationList() {
          try {
              const response = await axios.post(
                  "https://" + authData.regionFloatIp + ":32800/rest/pvms/web/station/v1/station/station-list",
                  {
                      "locale": "de_DE",
                      "sortId": "createTime",
                      "timeZone": "2.00",
                      "pageSize": "11",
                      "supportMDevice": "1",
                      "sortDir": "DESC",
                      "curPage": 1
                  },
                  {
                      headers: {
                          'roaRand': authData.roaRand,
                          'Cookie': 'locale=de-de;bspsession=' + authData.accessToken + ';dp-session=' + authData.accessToken + '; Secure; HttpOnly',
                          "Content-Type": "application/json"
                      },
                      httpsAgent: CONFIG.httpsAgent
                  }
              );
              log("Station-Liste: " + JSON.stringify(response.data), 'info');
              const stationList = response.data.data.list[0];
              await createAndSetObjects('huawei-smart-charger.Station', stationList);
          } catch (error) {
              log("Fehler beim Abrufen der Station-Liste: " + error.message, 'error');
          }
      }
      
      // Wallbox-Informationen abrufen
      async function getWallboxInfo() {
          try {
              const parentDn = getState('huawei-smart-charger.Station.dn').val;
              if (!parentDn) {
                  await getUserDetailInfo();
                  await getServerInfo();
                  await getStationList();
                  return await getWallboxInfo();
              }
      
              const response = await axios.post(
                  "https://" + authData.regionFloatIp + `:32800/rest/neteco/web/config/device/v1/device-list`,
                  "conditionParams.curPage=0&conditionParams.mocTypes=60080&conditionParams.parentDn=" + parentDn + "&conditionParams.recordperpage=500",
                  {
                      headers: {
                          'roaRand': authData.roaRand,
                          'Cookie': 'locale=de-de;bspsession=' + authData.accessToken + ';dp-session=' + authData.accessToken + '; Secure; HttpOnly',
                          "Content-Type": "application/x-www-form-urlencoded"
                      },
                      httpsAgent: CONFIG.httpsAgent
                  }
              );
      
              log("Wallbox-Informationen: " + JSON.stringify(response.data), 'debug');
              const wallboxInfo = response.data.data[0];
      
              // Erstelle den Basisordner für die Wallbox-Informationen
              const basePath = `huawei-smart-charger.WallboxInfo`;
      
              // Speichere alle Daten in IoBroker, einschließlich paramValues
              for (const key in wallboxInfo) {
                  if (key === 'paramValues') {
                      // Speziell für paramValues
                      const paramValuesPath = `${basePath}.paramValues`;
                      for (const paramKey in wallboxInfo.paramValues) {
                          const paramValue = wallboxInfo.paramValues[paramKey];
                          await setObject(`${paramValuesPath}.${paramKey}`, {
                              type: 'state',
                              common: {
                                  name: `Parameter ${paramKey}`,
                                  type: typeof paramValue,
                                  role: 'info',
                                  read: true,
                                  write: WRITABLE_IDS.includes(parseInt(paramKey)) // Schreibbare IDs berücksichtigen
                              },
                              native: { id: paramKey, value: paramValue }
                          });
                          await setState(`${paramValuesPath}.${paramKey}`, paramValue, true);
                      }
                  } else {
                      // Speichere alle anderen Daten in IoBroker
                      await setObject(`${basePath}.${key}`, {
                          type: 'state',
                          common: {
                              name: key,
                              type: typeof wallboxInfo[key],
                              role: 'info',
                              read: true,
                              write: false
                          },
                          native: { value: wallboxInfo[key] }
                      });
                      await setState(`${basePath}.${key}`, wallboxInfo[key], true);
                  }
              }
      
              // Speichere die dnId explizit im Basisordner
              const dnId = wallboxInfo.dnId;
              await setState(`${basePath}.dnId`, dnId, true);
      
              // Rufe die Wallbox-Konfigurationsinformationen auf, wenn paramValues vorhanden sind
              if (wallboxInfo.paramValues) {
                  await getWallboxConfigInfo(dnId, wallboxInfo.paramValues);
              }
          } catch (error) {
              log("Fehler beim Abrufen der Wallbox-Informationen: " + error.message, 'error');
          }
      }
      
      
      
      on({ id: new RegExp('^huawei-smart-charger\\.Wallbox\\.Settings\\.[^.]+$'), change: 'ne' }, async (obj) => {
          if (obj.state.ack) {
              return; // Wenn die Änderung von der API bestätigt wurde, ignoriere sie
          }
      
          const writableId = obj.native?.id;
          if (!writableId || !WRITABLE_IDS.includes(writableId)) {
              log(`Keine beschreibbare ID für ${obj.id} gefunden.`, 'warn');
              return;
          }
      
          try {
              // Verwende die gespeicherte dnId aus dem Objekt
              const dnId = getState(`${obj.id.replace('.Settings.', '.Settings.dnId')}`).val;
              if (!authData || (authData && new Date().getTime() > authData.expiryTime)) {
                  await authenticateAndScheduleRenewal();
              }
      
              if (authData && dnId) {
                  const requestData = {
                      changeValues: [{ id: writableId, value: obj.state.val }],
                      dnId: dnId
                  };
      
                  log(`Sende Anfrage mit Daten: ${JSON.stringify(requestData)}`, 'debug');
      
                  const response = await axios.post(
                      "https://" + authData.regionFloatIp + ":32800/rest/neteco/web/homemgr/v1/device/set-config-info",
                      JSON.stringify(requestData),
                      {
                          headers: {
                              'roaRand': authData.roaRand,
                              'Cookie': `locale=de-de;bspsession=${authData.accessToken};dp-session=${authData.accessToken}; Secure; HttpOnly`,
                              'Content-Type': 'application/json',
                              'x-timezone-offset': '120',
                              'client-info': '_manufacturer=iPhone;_model=iPhone;_os_ver=18.0.1;_os=iOS;_app_ver=24.6.102006;_package_name=com.huawei.smartpvms;appClientId=86366133-B8B5-41FA-8EB9-E5A64229E3D5',
                              'x-requested-with': 'XMLHttpRequest',
                              'User-Agent': 'iCleanPower/24.6.102006 (iPhone; iOS 18.0.1; Scale/3.00)',
                              'Accept-Language': 'de-DE;q=1, en-DE;q=0.9, zh-Hans-DE;q=0.8',
                              'Accept': '*/*'
                          },
                          httpsAgent: CONFIG.httpsAgent
                      }
                  );
      
                  log(`Antwort vom Server: ${JSON.stringify(response.data)}`, 'info');
                  if (response.data && response.data.code === 0) {
                      await setState(obj.id, obj.state.val, true);
                  }
              }
          } catch (error) {
              log(`Fehler beim Ändern des Werts für ${obj.id}: ${error.message}`, 'error');
              if (error.response) {
                  log(`Fehlerantwort vom Server: ${JSON.stringify(error.response.data)}`, 'error');
              }
          }
      });
      // Wallbox-Einstellungen abrufen und Konfigurationsinformationen anfordern
      async function getWallboxSettings() {
          const parentDn = getState('huawei-smart-charger.WallboxInfo.dn').val;
          try {
              if (!parentDn) {
                  await getWallboxInfo();
                  return await getWallboxSettings();
              }
      
              const response = await axios.get(
                  "https://" + authData.regionFloatIp + `:32800/rest/neteco/web/config/device/v1/children-list?conditionParams.curPage=0&conditionParams.mocTypes=60081&conditionParams.parentDn=${encodeURIComponent(parentDn)}&conditionParams.recordperpage=1`,
                  {
                      headers: {
                          'roaRand': authData.roaRand,
                          'Cookie': 'locale=de-de;bspsession=' + authData.accessToken + ';dp-session=' + authData.accessToken + '; Secure; HttpOnly'
                      },
                      httpsAgent: CONFIG.httpsAgent
                  }
              );
      
              log(`Wallbox-Einstellungen für ${parentDn}: ` + JSON.stringify(response.data), 'info');
              const wallboxSettings = response.data.data[0];
      
              // Speichern der dnId
              const dnId = wallboxSettings.dnId;
              //setState('huawei-smart-charger.WallboxSettings.dnId', dnId, true);
      
              // Erstelle die Struktur für paramValues und andere Daten
              const basePath = `huawei-smart-charger.WallboxSettings.${dnId}`;
      
              // Speichere alle Schlüssel von wallboxSettings in IoBroker, einschließlich paramValues
              for (const key in wallboxSettings) {
                  if (key === 'paramValues') {
                      // Speziell für paramValues
                      const paramValuesPath = `${basePath}.paramValues`;
                      for (const paramKey in wallboxSettings.paramValues) {
                          const paramValue = wallboxSettings.paramValues[paramKey];
                          await setObject(`${paramValuesPath}.${paramKey}`, {
                              type: 'state',
                              common: {
                                  name: `Parameter ${paramKey}`,
                                  type: typeof paramValue,
                                  role: 'info',
                                  read: true,
                                  write: WRITABLE_IDS.includes(parseInt(paramKey)) // Schreibbare IDs berücksichtigen
                              },
                              native: { id: paramKey, value: paramValue }
                          });
                          await setState(`${paramValuesPath}.${paramKey}`, paramValue, true);
                      }
                  } else {
                      // Speichere alle anderen Daten in IoBroker
                      await setObject(`${basePath}.${key}`, {
                          type: 'state',
                          common: {
                              name: key,
                              type: typeof wallboxSettings[key],
                              role: 'info',
                              read: true,
                              write: false
                          },
                          native: { value: wallboxSettings[key] }
                      });
                      await setState(`${basePath}.${key}`, wallboxSettings[key], true);
                  }
              }
      
              // Nur beim ersten Mal die Wallbox-Konfigurationsinformationen abrufen
              if (!getWallboxConfigInfo.calledWallboxSettings) {
                  await getWallboxConfigInfo(dnId, wallboxSettings.paramValues);
                  getWallboxConfigInfo.calledWallboxSettings = true;
              }
          } catch (error) {
              log(`Fehler beim Abrufen der Wallbox-Einstellungen für ${parentDn}: ${error.message}`, 'info');
          }
      }
      
      // Wallbox-Konfigurationsinformationen abrufen und in den entsprechenden Pfaden anlegen
      async function getWallboxConfigInfo(dnId, paramValues) {
          if (!paramValues) {
              log(`Keine Parameterwerte für dnId ${dnId} gefunden.`, 'info');
              return;
          }
      
          for (const id of Object.keys(paramValues)) {
              try {
                  const conditions = [{ queryAll: 0, signals: [id], dnId }];
                  const response = await axios.post(
                      "https://" + authData.regionFloatIp + ":32800/rest/neteco/web/homemgr/v1/device/get-config-info",
                      JSON.stringify({ conditions }),
                      {
                          headers: {
                              'roaRand': authData.roaRand,
                              'Cookie': `locale=de-de;bspsession=${authData.accessToken};dp-session=${authData.accessToken}; Secure; HttpOnly`,
                              "Content-Type": "application/json"
                          },
                          httpsAgent: CONFIG.httpsAgent
                      }
                  );
      
                  log(`Wallbox-Konfigurationsinformationen für ${dnId}, Signal ${id}: ` + JSON.stringify(response.data), 'debug');
                  const wallboxConfigInfo = response.data;
                  if (wallboxConfigInfo && wallboxConfigInfo[dnId] && wallboxConfigInfo[dnId][0]) {
                      const { name, realValue, value, enumMap, unit } = wallboxConfigInfo[dnId][0];
                      if (!name) continue;
      
                      // Sanitize the object ID, but not the display name
                      const sanitizedKey = name
                          .replace(/ä/g, 'ae')
                          .replace(/ö/g, 'oe')
                          .replace(/ü/g, 'ue')
                          .replace(/Ä/g, 'Ae')
                          .replace(/Ö/g, 'Oe')
                          .replace(/Ü/g, 'Ue')
                          .replace(/ß/g, 'ss')
                          .replace(/\s+/g, '_')
                          .replace(/[^\w\d_]/g, '');
      
      
                      // Speichere in huawei-smart-charger.Wallbox.Values
                      const key = sanitizedKey;
                      const stateValue = enumMap && Object.keys(enumMap).length > 0 ? value : realValue;
                      const valuePath = `huawei-smart-charger.Wallbox.Values.${key}`;
                      const settingsPath = `huawei-smart-charger.Wallbox.Settings.${key}`;
      
                      // Objekt in Values erstellen
                      await setObject(valuePath, {
                          type: 'state',
                          common: {
                              name: name, // Keep the original name here
                              type: typeof stateValue,
                              role: 'info',
                              read: true,
                              write: WRITABLE_IDS.includes(parseInt(id)),
                              unit: unit || undefined,
                              states: Object.keys(enumMap).length > 0 ? enumMap : undefined,
                              dnId: dnId // Speichern der dnId in common
                          },
                          native: wallboxConfigInfo[dnId][0]
                      });
                      await setState(valuePath, stateValue, true);
      
                      // Wenn das Objekt schreibbar ist, auch in Settings erstellen
                      if (WRITABLE_IDS.includes(parseInt(id))) {
                          await setObject(settingsPath, {
                              type: 'state',
                              common: {
                                  name: name, // Keep the original name here
                                  type: typeof stateValue,
                                  role: 'info',
                                  read: true,
                                  write: true,
                                  unit: unit || undefined,
                                  states: Object.keys(enumMap).length > 0 ? enumMap : undefined,
                                  dnId: dnId // Speichern der dnId in common
                              },
                              native: wallboxConfigInfo[dnId][0]
                          });
                          await setState(settingsPath, stateValue, true);
                      }
                  }
              } catch (error) {
                  log(`Fehler beim Abrufen der Wallbox-Konfigurationsinformationen für ${dnId}, Signal ${id}: ${error.message}`, 'error');
              }
          }
      }
      
      
      async function createAndSetObjects(basePath, data) {
          if (!data) {
              log(`Daten für ${basePath} sind null oder undefined.`, 'error');
              return;
          }
      
          for (const key in data) {
              if (data.hasOwnProperty(key)) {
                  const value = data[key];
                  // Ersetze Leerzeichen im Objektnamen durch '_'
                  const sanitizedKey = key.replace(/\s+/g, '_');
                  const id = `${basePath}.${sanitizedKey}`;
                  const objType = typeof value === 'object' && value !== null ? 'channel' : 'state';
      
                  log(`Versuche, Objekt ${id} zu erstellen. Typ: ${objType}, Wert: ${JSON.stringify(value)}`, 'info');
      
                  await setObject(id, {
                      type: objType,
                      common: {
                          name: sanitizedKey,
                          type: typeof value,
                          role: objType === 'channel' ? 'folder' : 'state',
                          read: true,
                          write: WRITABLE_IDS.includes(parseInt(key))
                      },
                      native: typeof value === 'object' && value !== null ? value : { value: value }
                  });
      
                  if (objType === 'state' && value !== null && value !== undefined) {
                      await setState(id, value, true);
                  } else if (objType === 'channel' && value !== null) {
                      // Rekursiv verschachtelte Objekte verarbeiten
                      await createAndSetObjects(id, value);
                  }
              }
          }
      }
      
      
      // Aktualisierung des Verbindungsstatus
      function updateConnectionState(isConnected) {
          try {
              setState('huawei-smart-charger.info.connection', isConnected, true);
          } catch (error) {
              log(`Fehler beim Aktualisieren des Verbindungsstatus: ${error.message}`, 'error');
          }
      }
      
      // Hauptlogik zur Authentifizierung und Datenabfrage
      async function main() {
          await authenticateAndScheduleRenewal();
          if (!authData) return;
      
          await getUserDetailInfo();
          await getServerInfo();
          await getStationList();
          await getWallboxInfo();
          await getWallboxSettings();
          await getChargeStatus();
          
      }
      
      // Lausche auf Änderungen der Settings und sende PUT-Anfrage an die API
      on({ id: new RegExp('^huawei-smart-charger\\.Wallbox\\.Settings\\.[^.]+$'), change: 'ne' }, async (obj) => {
          if (obj.state.ack) {
              return; // Wenn die Änderung von der API bestätigt wurde, ignoriere sie
          }
      
          const writableId = obj.native?.id;
          if (!writableId || !WRITABLE_IDS.includes(writableId)) {
              log(`Keine beschreibbare ID für ${obj.id} gefunden.`, 'warn');
              return;
          }
      
          try {
              // Lese die dnId aus dem Objekt in common
              const dnId = getObject(obj.id).common.dnId;
              if (!authData || (authData && new Date().getTime() > authData.expiryTime)) {
                  await authenticateAndScheduleRenewal();
              }
      
              if (authData && dnId) {
                  const requestData = {
                      changeValues: [{ id: writableId, value: obj.state.val }],
                      dnId: dnId
                  };
      
                  log(`Sende Anfrage mit Daten: ${JSON.stringify(requestData)}`, 'debug');
      
                  const response = await axios.post(
                      "https://" + authData.regionFloatIp + ":32800/rest/neteco/web/homemgr/v1/device/set-config-info",
                      JSON.stringify(requestData),
                      {
                          headers: {
                              'roaRand': authData.roaRand,
                              'Cookie': `locale=de-de;bspsession=${authData.accessToken};dp-session=${authData.accessToken}; Secure; HttpOnly`,
                              'Content-Type': 'application/json',
                              'x-timezone-offset': '120',
                              'client-info': '_manufacturer=iPhone;_model=iPhone;_os_ver=18.0.1;_os=iOS;_app_ver=24.6.102006;_package_name=com.huawei.smartpvms;appClientId=86366133-B8B5-41FA-8EB9-E5A64229E3D5',
                              'x-requested-with': 'XMLHttpRequest',
                              'User-Agent': 'iCleanPower/24.6.102006 (iPhone; iOS 18.0.1; Scale/3.00)',
                              'Accept-Language': 'de-DE;q=1, en-DE;q=0.9, zh-Hans-DE;q=0.8',
                              'Accept': '*/*'
                          },
                          httpsAgent: CONFIG.httpsAgent
                      }
                  );
      
                  log(`Antwort vom Server: ${JSON.stringify(response.data)}`, 'debug');
                  if (response.data) {
                      await setState(obj.id, obj.state.val, true);
                  }
                  await getWallboxInfo();
                  await getWallboxSettings();
              }
          } catch (error) {
              log(`Fehler beim Ändern des Werts für ${obj.id}: ${error.message}`, 'error');
              if (error.response) {
                  log(`Fehlerantwort vom Server: ${JSON.stringify(error.response.data)}`, 'error');
              }
          }
      });
      
      // Monitor changes in WallboxSettings and WallboxInfo under paramValues
      on({ id: new RegExp('^huawei-smart-charger\\.Wallbox(Settings|Info)\\.[^.]+\\.paramValues\\.[^.]+$'), change: 'ne' }, async (obj) => {
          if (obj.state.ack) {
              return; // If the change was confirmed by the API, ignore it
          }
      
          try {
              // Extract the parameter ID from the changed paramValues instance
              const paramId = parseInt(obj.id.split('.').pop()); // Extract the parameter ID from the object path
      
              // Define a helper function to update corresponding objects
              const updateObjects = async (basePath) => {
                  getObjectView('system', 'state', { startkey: basePath, endkey: basePath + "\u9999" }, async (err, allObjects) => {
                      if (err) {
                          log(`Error fetching objects from ${basePath}: ${err.message}`, 'error');
                          return;
                      }
      
                      for (const obj of allObjects.rows) {
                          const nativeId = obj.value.native?.id;
                          if (nativeId === paramId) {
                              // Update the state in the corresponding object
                              const newValue = obj.state.val;
                              await setState(obj.id, newValue, true);
                              log(`Updated value in ${obj.id} to: ${newValue}`, 'info');
                          }
                      }
                  });
              };
      
              // Update the corresponding objects in Wallbox.Values and Wallbox.Settings
              await updateObjects('huawei-smart-charger.Wallbox.Values.');
              await updateObjects('huawei-smart-charger.Wallbox.Settings.');
      
          } catch (error) {
              log(`Error while updating Wallbox.Values or Wallbox.Settings from paramValues change: ${error.message}`, 'error');
          }
      });
      
      // Ladestatus abfragen
      async function getChargeStatus() {
          try {
              // Fetch the dnId from the IoBroker state
              const dnId = getState('huawei-smart-charger.WallboxInfo.dnId').val;
              if (!dnId) {
                  log('dnId not found for getChargeStatus', 'warn');
                  return;
              }
      
              // Construct the request payload based on the provided curl example
              const requestData = {
                  gunNumber: 1, // Fixed value as per the example
                  needRealTimeStatus: false, // This will be toggled based on the interval logic
                  dnId: dnId
              };
      
              // Perform the POST request
              const response = await axios.post(
                  "https://" + authData.regionFloatIp + ":32800/rest/neteco/web/homemgr/v1/charger/status/charge-status",
                  JSON.stringify(requestData),
                  {
                      headers: {
                          'roaRand': authData.roaRand,
                          'Cookie': `locale=de-de;bspsession=${authData.accessToken};dp-session=${authData.accessToken}; Secure; HttpOnly`,
                          'Content-Type': 'application/json',
                          'x-timezone-offset': '120',
                          'client-info': '_manufacturer=iPhone;_model=iPhone;_os_ver=18.0.1;_os=iOS;_app_ver=24.6.102006;_package_name=com.huawei.smartpvms;appClientId=86366133-B8B5-41FA-8EB9-E5A64229E3D5',
                          'x-requested-with': 'XMLHttpRequest',
                          'User-Agent': 'iCleanPower/24.6.102006 (iPhone; iOS 18.0.1; Scale/3.00)',
                          'Accept-Language': 'de-DE;q=1, en-DE;q=0.9, zh-Hans-DE;q=0.8',
                          'Accept': '*/*'
                      },
                      httpsAgent: CONFIG.httpsAgent
                  }
              );
      
              // Log the charge status response for testing
              log(`Charge Status response: ${JSON.stringify(response.data)}`, 'info');
      
              // Update interval based on the charge status
              if (response.data && response.data.chargeStatus !== undefined) {
                  const status = response.data.chargeStatus;
                  log(`Current charge status: ${status}`, 'info');
                  scheduleIntervals(status); // Update intervals based on the charge status
              } else {
                  log(`Invalid response from getChargeStatus: ${JSON.stringify(response.data)}`, 'warn');
              }
      
          } catch (error) {
              log(`Fehler beim Abrufen des Ladestatus: ${error.message}`, 'error');
              if (error.response) {
                  log(`Fehlerantwort vom Server: ${JSON.stringify(error.response.data)}`, 'error');
              }
          }
      }
      
      // Schedule intervals based on the charge status
      function scheduleIntervals(chargeStatus) {
          let intervalTime = 300000; // Default interval: 5 minutes
          let needRealTimeStatus = false;
      
          // Define specific interval times based on the charge status
          if ([3, 4, 7, 8].includes(chargeStatus)) {
              intervalTime = 60000; // 30 seconds for these statuses
              needRealTimeStatus = true; // Enable real-time status when charging or in related states
          } else if ([1, 2, 6, 10, 11].includes(chargeStatus)) {
              intervalTime = 180000; // 3 minutes for these statuses
          }
      
          // Clear any existing intervals
          clearInterval(infoInterval);
          clearInterval(settingsInterval);
      
          // Schedule intervals with the appropriate time
          infoInterval = setInterval(async () => {
              await getWallboxInfo(needRealTimeStatus); // Fetch wallbox info at the set interval
          }, intervalTime);
      
          settingsInterval = setInterval(async () => {
              await getWallboxSettings(needRealTimeStatus); // Fetch wallbox settings at the set interval
          }, intervalTime);
      
          log(`Scheduled intervals: ${intervalTime / 1000} seconds`, 'info');
      }
      
      
      // Initial call to getChargeStatus and start checking intervals
      let infoInterval, settingsInterval;
      async function checkChargeInterval() {
          await getChargeStatus(); // Check the charge status initially and set intervals
          setInterval(async () => {
              await getChargeStatus(); // Re-check the charge status at regular intervals
          }, CONFIG.interval);
      }
      
      
      
      main();
      
      
      B Offline
      B Offline
      baerengraben
      schrieb am zuletzt editiert von baerengraben
      #14

      @stolly82 Ich habe es kurz getestet. Beim ersten Start werden viele Warnungen in der Art geworfen:

      11.11.2024, 14:26:50.504	[warn ]: javascript.0 (19439)     at getWallboxSettings (script.js.common.Wallbox:348:23)
      11.11.2024, 14:26:50.504	[warn ]: javascript.0 (19439)     at getWallboxSettings (script.js.common.Wallbox:291:20)
      11.11.2024, 14:26:50.504	[warn ]: javascript.0 (19439)     at main (script.js.common.Wallbox:510:5)
      
      

      Aber die Daten kommen zu Beginn gut an. Die Logik der Objektstruktur habe ich aber noch nicht durchschaut. Auch habe ich es noch nicht geschafft die Wallbox-Einstellungen zu verändern. Super wäre es z.B. wenn ich den Arbeitsmodus (huawei-smart-charger.Wallbox.Settings.Arbeitsmodus) verändern könnte. Das setzen des "Manuellen Modus" scheint zu funktionieren. Das Setzen von "PV Überschuss" aber nicht.

      Auch scheint es da noch ein Problem bei der regelmässigen Aktualisierung zu geben. Wenn ich in der FusionSolar-App von "PV Überschuss" nach "Manuellen Modus" wechsle, wird das irgendwie nicht vom Script in den Objekten aktualisiert. Dies auch nicht nach einem Sync ( 5min Scheduler).

      Das gleiche Verhalten auch bei huawei-smart-charger.Wallbox.Settings.Wechsel_zwischen_ein_und_dreiphasig. Der lässt sich über das Script bei mir nicht setzen.

      Welche Werte können in den Objekten verändert werden bzw. werden zurück auf die Wallbox geschrieben? Einfach jene unter huawei-smart-charger.Wallbox.Settings?

      M 1 Antwort Letzte Antwort
      0
      • B baerengraben

        @stolly82 Ich habe es kurz getestet. Beim ersten Start werden viele Warnungen in der Art geworfen:

        11.11.2024, 14:26:50.504	[warn ]: javascript.0 (19439)     at getWallboxSettings (script.js.common.Wallbox:348:23)
        11.11.2024, 14:26:50.504	[warn ]: javascript.0 (19439)     at getWallboxSettings (script.js.common.Wallbox:291:20)
        11.11.2024, 14:26:50.504	[warn ]: javascript.0 (19439)     at main (script.js.common.Wallbox:510:5)
        
        

        Aber die Daten kommen zu Beginn gut an. Die Logik der Objektstruktur habe ich aber noch nicht durchschaut. Auch habe ich es noch nicht geschafft die Wallbox-Einstellungen zu verändern. Super wäre es z.B. wenn ich den Arbeitsmodus (huawei-smart-charger.Wallbox.Settings.Arbeitsmodus) verändern könnte. Das setzen des "Manuellen Modus" scheint zu funktionieren. Das Setzen von "PV Überschuss" aber nicht.

        Auch scheint es da noch ein Problem bei der regelmässigen Aktualisierung zu geben. Wenn ich in der FusionSolar-App von "PV Überschuss" nach "Manuellen Modus" wechsle, wird das irgendwie nicht vom Script in den Objekten aktualisiert. Dies auch nicht nach einem Sync ( 5min Scheduler).

        Das gleiche Verhalten auch bei huawei-smart-charger.Wallbox.Settings.Wechsel_zwischen_ein_und_dreiphasig. Der lässt sich über das Script bei mir nicht setzen.

        Welche Werte können in den Objekten verändert werden bzw. werden zurück auf die Wallbox geschrieben? Einfach jene unter huawei-smart-charger.Wallbox.Settings?

        M Offline
        M Offline
        mhuber
        schrieb am zuletzt editiert von
        #15

        @baerengraben sagte in Huawei Wallbox - S Charger (7kw/h / 22kw/h) Adapter test:

        @stolly82 Ich habe es kurz getestet. Beim ersten Start werden viele Warnungen in der Art geworfen:

        11.11.2024, 14:26:50.504	[warn ]: javascript.0 (19439)     at getWallboxSettings (script.js.common.Wallbox:348:23)
        11.11.2024, 14:26:50.504	[warn ]: javascript.0 (19439)     at getWallboxSettings (script.js.common.Wallbox:291:20)
        11.11.2024, 14:26:50.504	[warn ]: javascript.0 (19439)     at main (script.js.common.Wallbox:510:5)
        
        

        Aber die Daten kommen zu Beginn gut an. Die Logik der Objektstruktur habe ich aber noch nicht durchschaut. Auch habe ich es noch nicht geschafft die Wallbox-Einstellungen zu verändern. Super wäre es z.B. wenn ich den Arbeitsmodus (huawei-smart-charger.Wallbox.Settings.Arbeitsmodus) verändern könnte. Das setzen des "Manuellen Modus" scheint zu funktionieren. Das Setzen von "PV Überschuss" aber nicht.

        Auch scheint es da noch ein Problem bei der regelmässigen Aktualisierung zu geben. Wenn ich in der FusionSolar-App von "PV Überschuss" nach "Manuellen Modus" wechsle, wird das irgendwie nicht vom Script in den Objekten aktualisiert. Dies auch nicht nach einem Sync ( 5min Scheduler).

        Das gleiche Verhalten auch bei huawei-smart-charger.Wallbox.Settings.Wechsel_zwischen_ein_und_dreiphasig. Der lässt sich über das Script bei mir nicht setzen.

        Welche Werte können in den Objekten verändert werden bzw. werden zurück auf die Wallbox geschrieben? Einfach jene unter huawei-smart-charger.Wallbox.Settings?

        hab auch kurz getestet, dachte es geht nicht da mein log übergegangen ist aber die Werte sind da :-)

        1 Antwort Letzte Antwort
        0
        • stolly82S Offline
          stolly82S Offline
          stolly82
          schrieb am zuletzt editiert von
          #16

          Die Fehlermeldung zum Start mache ich noch weg.

          Also das Loggen der API Calls aus der App war nicht gerade das einfachste, bis ich die Calls raus hatte die da was machen und wann diese von der APP abgerufen und gesetzt werden,... und was da aus welchen Calls rein muss.

          Es gibt in der App mehre API Calls, die nur beim öffnen der Wallbox aufgerufen werden (einmalig) und Live calls, die nur nach dem verstellen von Werten einmalig abgerufen werden.

          Die Wallbox ist in 2 unterschiedlichen API Calls vorhanden und wird in den Wallbox.Settings und Wallbox.Values zusammengelegt (Die anderen WallboxInfo & WallboxSettings sind die Responses aus den APIs, so wie sie raus kommen).

          WallboxInfo & WallboxSettings sind auch unbenannt in der API, werden also nur als ID ausgegeben, die man dann alle einzeln über eine API abfragen muss, wie diese heissen.

          Die IDs die beschreibbar sind, habe ich durch das API logging recherchiert, ich glaube aber da habe ich irgendwas falsch aufgeschrieben, denn ich habe mit Garantie die IP Adresse in der App nicht geändert.
          Vielleicht mal die IDs ausprobieren die euch noch fehlen, die dann einfach in die WRITABLE_IDS eintragen, theoretisch sollten die Datenpunkte dann in Wallbox.Settings erscheinen.
          Nur in denen Werte ändert, darauf lauscht der listener.

          Die IDs findet Ihr dann in den Wallbox > Values > Objektdaten
          8cf25280-846a-4c04-b5a9-eadc23b6b420-image.png

          B 1 Antwort Letzte Antwort
          1
          • stolly82S stolly82

            Die Fehlermeldung zum Start mache ich noch weg.

            Also das Loggen der API Calls aus der App war nicht gerade das einfachste, bis ich die Calls raus hatte die da was machen und wann diese von der APP abgerufen und gesetzt werden,... und was da aus welchen Calls rein muss.

            Es gibt in der App mehre API Calls, die nur beim öffnen der Wallbox aufgerufen werden (einmalig) und Live calls, die nur nach dem verstellen von Werten einmalig abgerufen werden.

            Die Wallbox ist in 2 unterschiedlichen API Calls vorhanden und wird in den Wallbox.Settings und Wallbox.Values zusammengelegt (Die anderen WallboxInfo & WallboxSettings sind die Responses aus den APIs, so wie sie raus kommen).

            WallboxInfo & WallboxSettings sind auch unbenannt in der API, werden also nur als ID ausgegeben, die man dann alle einzeln über eine API abfragen muss, wie diese heissen.

            Die IDs die beschreibbar sind, habe ich durch das API logging recherchiert, ich glaube aber da habe ich irgendwas falsch aufgeschrieben, denn ich habe mit Garantie die IP Adresse in der App nicht geändert.
            Vielleicht mal die IDs ausprobieren die euch noch fehlen, die dann einfach in die WRITABLE_IDS eintragen, theoretisch sollten die Datenpunkte dann in Wallbox.Settings erscheinen.
            Nur in denen Werte ändert, darauf lauscht der listener.

            Die IDs findet Ihr dann in den Wallbox > Values > Objektdaten
            8cf25280-846a-4c04-b5a9-eadc23b6b420-image.png

            B Offline
            B Offline
            baerengraben
            schrieb am zuletzt editiert von baerengraben
            #17

            @stolly82 Merci für die Infos :) Aber verstehe ich das richtig, dass du das Script nicht basierend auf einer API Beschreibung von Huawei sondern basierend auf einer Analyse der App Kommunikation zum Backend entwickelt hast? Also quasi "reverse engineered"?

            stolly82S 1 Antwort Letzte Antwort
            0
            • B baerengraben

              @stolly82 Merci für die Infos :) Aber verstehe ich das richtig, dass du das Script nicht basierend auf einer API Beschreibung von Huawei sondern basierend auf einer Analyse der App Kommunikation zum Backend entwickelt hast? Also quasi "reverse engineered"?

              stolly82S Offline
              stolly82S Offline
              stolly82
              schrieb am zuletzt editiert von
              #18

              @baerengraben

              :grinning: :grinning: :grinning: :grinning: :grinning: :grinning: ,...nicht basierend auf einer API Beschreibung von Huawei :grinning: :grinning: :grinning: :grinning: :grinning: :grinning:

              Das ist komplettes Reverse Engineering, Offiziell gibt es überhaupt nichts von Huawei und die werden es auch nicht einbinden.

              Die wollen OCPP machen, release irgendwie Mitte 2023,...

              Ich bin da ziemlich im Thema mit den HomeAssistant Junx, da ich denne geholfen habe Modbus und jetzt die App API mit einzubinden.

              B M 2 Antworten Letzte Antwort
              1
              • stolly82S stolly82

                @baerengraben

                :grinning: :grinning: :grinning: :grinning: :grinning: :grinning: ,...nicht basierend auf einer API Beschreibung von Huawei :grinning: :grinning: :grinning: :grinning: :grinning: :grinning:

                Das ist komplettes Reverse Engineering, Offiziell gibt es überhaupt nichts von Huawei und die werden es auch nicht einbinden.

                Die wollen OCPP machen, release irgendwie Mitte 2023,...

                Ich bin da ziemlich im Thema mit den HomeAssistant Junx, da ich denne geholfen habe Modbus und jetzt die App API mit einzubinden.

                B Offline
                B Offline
                baerengraben
                schrieb am zuletzt editiert von
                #19

                @stolly82 Alles Klar :D Wie möchtest du die Test-Feedbacks erhalten? Am besten als Issue in github?

                1 Antwort Letzte Antwort
                0
                • stolly82S stolly82

                  @baerengraben

                  :grinning: :grinning: :grinning: :grinning: :grinning: :grinning: ,...nicht basierend auf einer API Beschreibung von Huawei :grinning: :grinning: :grinning: :grinning: :grinning: :grinning:

                  Das ist komplettes Reverse Engineering, Offiziell gibt es überhaupt nichts von Huawei und die werden es auch nicht einbinden.

                  Die wollen OCPP machen, release irgendwie Mitte 2023,...

                  Ich bin da ziemlich im Thema mit den HomeAssistant Junx, da ich denne geholfen habe Modbus und jetzt die App API mit einzubinden.

                  M Offline
                  M Offline
                  mhuber
                  schrieb am zuletzt editiert von
                  #20

                  @stolly82 OCPP meinst Mitte 2025 oder? Machst Du auch eine Adapter draus oder bleibts beim Script? Ich nehme an Du hast App API gemacht weil ja Modbus leider nicht geht wenn man schon den Virtuellen Zähler von Huawei mit der Wallbox hat, oder? Bei mir geht nämlich deswegen Modbus nicht....
                  Weiß ev. jemand ob Huawei jemals mehr als einen gleichzeitigen Modbus Client erlauben wird?

                  1 Antwort Letzte Antwort
                  0
                  • stolly82S Offline
                    stolly82S Offline
                    stolly82
                    schrieb am zuletzt editiert von
                    #21

                    @mhuber leider meinte ich nicht Mitte 2025, sondern Mitte 2023! Das war schon korrekt ;-)

                    Es sollte schon seit diversen FW Versionen drin sein, im HomeAssistant forum hatten Leute vor vor mehren Monaten eine Antwort von Huawei gepostet, dass die OCPP in der nächsten Firmware enthalten ist.

                    Danach gab es bereits 4 neue Versionen.

                    Die nerven die da bei Huawei auch richtig, aber das scheint denen wirklich egal zu sein.

                    Ich mache da dann einen Adapter aus dem Script (ist nur 10 min Arbeit das eben umzuschreiben).

                    Die Adapter sind super nervig beim Entwickeln, da schleichen sich bei mir immer Fehler ein die dann bei der Prüfung extrem aufwendig sind raus zu bekommen.
                    Das liegt irgendwie am Adapter Creator tool, daher schreibe ich sowas aktuell immer als javascript vor und wenn es fertig ist schiebe ich das in den Adapter rein.

                    Sind in der Regel nur Konfigurationen und der Objekt-Pfad "Adaptername.(instanz)." statt "Adaptername" die ich dann ändern muss.

                    @baerengraben
                    GIT macht sinn, kannst aber auch hier machen.

                    Wichtig sind dinge wie unter welchen bedingungen ggf. noch eine Abfrage schneller rein muss (Beispiel man ändert was, dann würde ja die Änderung gepusht zur WB aber der Adapter fragt erst im nächsten Zyklus wieder ab, ggf. will man das schneller im Adapter sehen, dass man nach einer Änderung den Zyklus minimiert oder so).

                    Oder wenn was nicht funktioniert.

                    Viel ist aus der API eh nicht raus zu holen, die dinge die was mit der WB zu tun haben, habe ich alle drin.

                    M 1 Antwort Letzte Antwort
                    1
                    • stolly82S stolly82

                      @mhuber leider meinte ich nicht Mitte 2025, sondern Mitte 2023! Das war schon korrekt ;-)

                      Es sollte schon seit diversen FW Versionen drin sein, im HomeAssistant forum hatten Leute vor vor mehren Monaten eine Antwort von Huawei gepostet, dass die OCPP in der nächsten Firmware enthalten ist.

                      Danach gab es bereits 4 neue Versionen.

                      Die nerven die da bei Huawei auch richtig, aber das scheint denen wirklich egal zu sein.

                      Ich mache da dann einen Adapter aus dem Script (ist nur 10 min Arbeit das eben umzuschreiben).

                      Die Adapter sind super nervig beim Entwickeln, da schleichen sich bei mir immer Fehler ein die dann bei der Prüfung extrem aufwendig sind raus zu bekommen.
                      Das liegt irgendwie am Adapter Creator tool, daher schreibe ich sowas aktuell immer als javascript vor und wenn es fertig ist schiebe ich das in den Adapter rein.

                      Sind in der Regel nur Konfigurationen und der Objekt-Pfad "Adaptername.(instanz)." statt "Adaptername" die ich dann ändern muss.

                      @baerengraben
                      GIT macht sinn, kannst aber auch hier machen.

                      Wichtig sind dinge wie unter welchen bedingungen ggf. noch eine Abfrage schneller rein muss (Beispiel man ändert was, dann würde ja die Änderung gepusht zur WB aber der Adapter fragt erst im nächsten Zyklus wieder ab, ggf. will man das schneller im Adapter sehen, dass man nach einer Änderung den Zyklus minimiert oder so).

                      Oder wenn was nicht funktioniert.

                      Viel ist aus der API eh nicht raus zu holen, die dinge die was mit der WB zu tun haben, habe ich alle drin.

                      M Offline
                      M Offline
                      mhuber
                      schrieb am zuletzt editiert von
                      #22

                      @stolly82 sagte in Huawei Wallbox - S Charger (7kw/h / 22kw/h) Adapter test:

                      @mhuber leider meinte ich nicht Mitte 2025, sondern Mitte 2023! Das war schon korrekt ;-)

                      Es sollte schon seit diversen FW Versionen drin sein, im HomeAssistant forum hatten Leute vor vor mehren Monaten eine Antwort von Huawei gepostet, dass die OCPP in der nächsten Firmware enthalten ist.

                      Danach gab es bereits 4 neue Versionen.

                      Die nerven die da bei Huawei auch richtig, aber das scheint denen wirklich egal zu sein.

                      Ich mache da dann einen Adapter aus dem Script (ist nur 10 min Arbeit das eben umzuschreiben).

                      Die Adapter sind super nervig beim Entwickeln, da schleichen sich bei mir immer Fehler ein die dann bei der Prüfung extrem aufwendig sind raus zu bekommen.
                      Das liegt irgendwie am Adapter Creator tool, daher schreibe ich sowas aktuell immer als javascript vor und wenn es fertig ist schiebe ich das in den Adapter rein.

                      Sind in der Regel nur Konfigurationen und der Objekt-Pfad "Adaptername.(instanz)." statt "Adaptername" die ich dann ändern muss.

                      @baerengraben
                      GIT macht sinn, kannst aber auch hier machen.

                      Wichtig sind dinge wie unter welchen bedingungen ggf. noch eine Abfrage schneller rein muss (Beispiel man ändert was, dann würde ja die Änderung gepusht zur WB aber der Adapter fragt erst im nächsten Zyklus wieder ab, ggf. will man das schneller im Adapter sehen, dass man nach einer Änderung den Zyklus minimiert oder so).

                      Oder wenn was nicht funktioniert.

                      Viel ist aus der API eh nicht raus zu holen, die dinge die was mit der WB zu tun haben, habe ich alle drin.

                      Super danke für die Infos. Aber für die Modbus Einbindung über einen Adapter gibts keinen Workaround oder? Wegen dem einen Client wenn man den Virtuellen Zähler nutzt oder?

                      1 Antwort Letzte Antwort
                      0
                      • stolly82S stolly82

                        Hier schon mal vorab das Javascript, das könnt Ihr zum testen so übernehmen!

                        Einfach oben die Zugangsdaten aus der mobilen App eingeben und fertig.
                        @baerengraben @Fabio

                        const axios = require('axios');
                        
                        // Konfiguration
                        const CONFIG = {
                            userName: 'MySUERNAME',
                            password: 'MyPASSWORD',
                            grantType: 'password',
                            appClientId: '86366133-B8B5-41FA-8EB9-E5A64229E3E1',
                            httpsAgent: new (require('https').Agent)({ rejectUnauthorized: false }),
                            interval: 1200000 // Intervall in Millisekunden für wiederkehrende Abfragen
                        };
                        
                        // Beschreibbare IDs (manuell festgelegt)
                        const WRITABLE_IDS = [
                            20001, 20002, 20004, 20005, 20006, 20010, 20011, 20013, 20015, 20016, 20017, 538976529, 538976290, 538976533, 538976534, 538976570, 538976800
                        ];
                        
                        
                        let authData = null;
                        
                        // Authentifizierung und Planung der Token-Erneuerung
                        async function authenticateAndScheduleRenewal() {
                            authData = await authenticate();
                            if (!authData) {
                                log('Authentifizierung fehlgeschlagen', 'error');
                                return;
                            }
                        
                            const refreshTime = (authData.expires - 300) * 1000; // Erneuerung 5 Minuten vor Ablauf
                            log(`Nächste Token-Erneuerung in ${(refreshTime / 1000 / 60).toFixed(2)} Minuten`, 'info');
                        
                            setTimeout(authenticateAndScheduleRenewal, refreshTime);
                        }
                        
                        // Authentifizierung
                        async function authenticate() {
                            try {
                                const response = await axios.post(
                                    "https://intl.fusionsolar.huawei.com:32800/rest/neteco/appauthen/v1/smapp/app/token",
                                    JSON.stringify({
                                        userName: CONFIG.userName,
                                        value: CONFIG.password,
                                        grantType: CONFIG.grantType,
                                        verifyCode: "",
                                        appClientId: CONFIG.appClientId
                                    }),
                                    {
                                        headers: {
                                            "Content-Type": "application/json"
                                        },
                                        httpsAgent: CONFIG.httpsAgent
                                    }
                                );
                        
                                if (response.data && response.data.data && response.data.data.accessToken) {
                                    log("Benutzer validiert. Antwort: " + JSON.stringify(response.data), 'info');
                                    setState('huawei-smart-charger.info.connection', true, true);
                                    response.data.data.expiryTime = new Date().getTime() + (response.data.data.expires * 1000);
                                    return response.data.data;
                                } else {
                                    log("Fehler bei der Authentifizierung: Ungültige Antwort. Antwort: " + JSON.stringify(response.data), 'error');
                                    setState('huawei-smart-charger.info.connection', false, true);
                                    return null;
                                }
                            } catch (error) {
                                log("Fehler bei der Authentifizierung: " + error.message, 'error');
                                setState('huawei-smart-charger.info.connection', false, true);
                                return null;
                            }
                        }
                        
                        // Benutzerinformationen abrufen
                        async function getUserDetailInfo() {
                            try {
                                const response = await axios.get(
                                    "https://" + authData.regionFloatIp + ':32800/rest/neteco/phoneapp/v1/datacenter/getuserdetailinfo',
                                    {
                                        headers: {
                                            'roaRand': authData.roaRand,
                                            'Cookie': 'locale=de-de;bspsession=' + authData.accessToken + ';dp-session=' + authData.accessToken + '; Secure; HttpOnly'
                                        },
                                        httpsAgent: CONFIG.httpsAgent
                                    }
                                );
                                log("Benutzerinformationen: " + JSON.stringify(response.data), 'info');
                                const userInfo = response.data;
                                await createAndSetObjects('huawei-smart-charger.User', userInfo);
                            } catch (error) {
                                log("Fehler beim Abrufen der Benutzerinformationen: " + error.message, 'error');
                            }
                        }
                        
                        // Serverinformationen abrufen
                        async function getServerInfo() {
                            try {
                                const response = await axios.get(
                                    "https://" + authData.regionFloatIp + ":32800/rest/neteco/phoneapp/v2/fusionsolarbusiness/company/getorganizationcompanybyuser",
                                    {
                                        headers: {
                                            'roaRand': authData.roaRand,
                                            'Cookie': 'locale=de-de;bspsession=' + authData.accessToken + ';dp-session=' + authData.accessToken + '; Secure; HttpOnly'
                                        },
                                        httpsAgent: CONFIG.httpsAgent
                                    }
                                );
                                log("Serverinformationen: " + JSON.stringify(response.data), 'info');
                                const serverInfo = response.data.data;
                                await createAndSetObjects('huawei-smart-charger.Server', serverInfo);
                            } catch (error) {
                                log("Fehler beim Abrufen der Serverinformationen: " + error.message, 'error');
                            }
                        }
                        
                        // Station-Liste abrufen
                        async function getStationList() {
                            try {
                                const response = await axios.post(
                                    "https://" + authData.regionFloatIp + ":32800/rest/pvms/web/station/v1/station/station-list",
                                    {
                                        "locale": "de_DE",
                                        "sortId": "createTime",
                                        "timeZone": "2.00",
                                        "pageSize": "11",
                                        "supportMDevice": "1",
                                        "sortDir": "DESC",
                                        "curPage": 1
                                    },
                                    {
                                        headers: {
                                            'roaRand': authData.roaRand,
                                            'Cookie': 'locale=de-de;bspsession=' + authData.accessToken + ';dp-session=' + authData.accessToken + '; Secure; HttpOnly',
                                            "Content-Type": "application/json"
                                        },
                                        httpsAgent: CONFIG.httpsAgent
                                    }
                                );
                                log("Station-Liste: " + JSON.stringify(response.data), 'info');
                                const stationList = response.data.data.list[0];
                                await createAndSetObjects('huawei-smart-charger.Station', stationList);
                            } catch (error) {
                                log("Fehler beim Abrufen der Station-Liste: " + error.message, 'error');
                            }
                        }
                        
                        // Wallbox-Informationen abrufen
                        async function getWallboxInfo() {
                            try {
                                const parentDn = getState('huawei-smart-charger.Station.dn').val;
                                if (!parentDn) {
                                    await getUserDetailInfo();
                                    await getServerInfo();
                                    await getStationList();
                                    return await getWallboxInfo();
                                }
                        
                                const response = await axios.post(
                                    "https://" + authData.regionFloatIp + `:32800/rest/neteco/web/config/device/v1/device-list`,
                                    "conditionParams.curPage=0&conditionParams.mocTypes=60080&conditionParams.parentDn=" + parentDn + "&conditionParams.recordperpage=500",
                                    {
                                        headers: {
                                            'roaRand': authData.roaRand,
                                            'Cookie': 'locale=de-de;bspsession=' + authData.accessToken + ';dp-session=' + authData.accessToken + '; Secure; HttpOnly',
                                            "Content-Type": "application/x-www-form-urlencoded"
                                        },
                                        httpsAgent: CONFIG.httpsAgent
                                    }
                                );
                        
                                log("Wallbox-Informationen: " + JSON.stringify(response.data), 'debug');
                                const wallboxInfo = response.data.data[0];
                        
                                // Erstelle den Basisordner für die Wallbox-Informationen
                                const basePath = `huawei-smart-charger.WallboxInfo`;
                        
                                // Speichere alle Daten in IoBroker, einschließlich paramValues
                                for (const key in wallboxInfo) {
                                    if (key === 'paramValues') {
                                        // Speziell für paramValues
                                        const paramValuesPath = `${basePath}.paramValues`;
                                        for (const paramKey in wallboxInfo.paramValues) {
                                            const paramValue = wallboxInfo.paramValues[paramKey];
                                            await setObject(`${paramValuesPath}.${paramKey}`, {
                                                type: 'state',
                                                common: {
                                                    name: `Parameter ${paramKey}`,
                                                    type: typeof paramValue,
                                                    role: 'info',
                                                    read: true,
                                                    write: WRITABLE_IDS.includes(parseInt(paramKey)) // Schreibbare IDs berücksichtigen
                                                },
                                                native: { id: paramKey, value: paramValue }
                                            });
                                            await setState(`${paramValuesPath}.${paramKey}`, paramValue, true);
                                        }
                                    } else {
                                        // Speichere alle anderen Daten in IoBroker
                                        await setObject(`${basePath}.${key}`, {
                                            type: 'state',
                                            common: {
                                                name: key,
                                                type: typeof wallboxInfo[key],
                                                role: 'info',
                                                read: true,
                                                write: false
                                            },
                                            native: { value: wallboxInfo[key] }
                                        });
                                        await setState(`${basePath}.${key}`, wallboxInfo[key], true);
                                    }
                                }
                        
                                // Speichere die dnId explizit im Basisordner
                                const dnId = wallboxInfo.dnId;
                                await setState(`${basePath}.dnId`, dnId, true);
                        
                                // Rufe die Wallbox-Konfigurationsinformationen auf, wenn paramValues vorhanden sind
                                if (wallboxInfo.paramValues) {
                                    await getWallboxConfigInfo(dnId, wallboxInfo.paramValues);
                                }
                            } catch (error) {
                                log("Fehler beim Abrufen der Wallbox-Informationen: " + error.message, 'error');
                            }
                        }
                        
                        
                        
                        on({ id: new RegExp('^huawei-smart-charger\\.Wallbox\\.Settings\\.[^.]+$'), change: 'ne' }, async (obj) => {
                            if (obj.state.ack) {
                                return; // Wenn die Änderung von der API bestätigt wurde, ignoriere sie
                            }
                        
                            const writableId = obj.native?.id;
                            if (!writableId || !WRITABLE_IDS.includes(writableId)) {
                                log(`Keine beschreibbare ID für ${obj.id} gefunden.`, 'warn');
                                return;
                            }
                        
                            try {
                                // Verwende die gespeicherte dnId aus dem Objekt
                                const dnId = getState(`${obj.id.replace('.Settings.', '.Settings.dnId')}`).val;
                                if (!authData || (authData && new Date().getTime() > authData.expiryTime)) {
                                    await authenticateAndScheduleRenewal();
                                }
                        
                                if (authData && dnId) {
                                    const requestData = {
                                        changeValues: [{ id: writableId, value: obj.state.val }],
                                        dnId: dnId
                                    };
                        
                                    log(`Sende Anfrage mit Daten: ${JSON.stringify(requestData)}`, 'debug');
                        
                                    const response = await axios.post(
                                        "https://" + authData.regionFloatIp + ":32800/rest/neteco/web/homemgr/v1/device/set-config-info",
                                        JSON.stringify(requestData),
                                        {
                                            headers: {
                                                'roaRand': authData.roaRand,
                                                'Cookie': `locale=de-de;bspsession=${authData.accessToken};dp-session=${authData.accessToken}; Secure; HttpOnly`,
                                                'Content-Type': 'application/json',
                                                'x-timezone-offset': '120',
                                                'client-info': '_manufacturer=iPhone;_model=iPhone;_os_ver=18.0.1;_os=iOS;_app_ver=24.6.102006;_package_name=com.huawei.smartpvms;appClientId=86366133-B8B5-41FA-8EB9-E5A64229E3D5',
                                                'x-requested-with': 'XMLHttpRequest',
                                                'User-Agent': 'iCleanPower/24.6.102006 (iPhone; iOS 18.0.1; Scale/3.00)',
                                                'Accept-Language': 'de-DE;q=1, en-DE;q=0.9, zh-Hans-DE;q=0.8',
                                                'Accept': '*/*'
                                            },
                                            httpsAgent: CONFIG.httpsAgent
                                        }
                                    );
                        
                                    log(`Antwort vom Server: ${JSON.stringify(response.data)}`, 'info');
                                    if (response.data && response.data.code === 0) {
                                        await setState(obj.id, obj.state.val, true);
                                    }
                                }
                            } catch (error) {
                                log(`Fehler beim Ändern des Werts für ${obj.id}: ${error.message}`, 'error');
                                if (error.response) {
                                    log(`Fehlerantwort vom Server: ${JSON.stringify(error.response.data)}`, 'error');
                                }
                            }
                        });
                        // Wallbox-Einstellungen abrufen und Konfigurationsinformationen anfordern
                        async function getWallboxSettings() {
                            const parentDn = getState('huawei-smart-charger.WallboxInfo.dn').val;
                            try {
                                if (!parentDn) {
                                    await getWallboxInfo();
                                    return await getWallboxSettings();
                                }
                        
                                const response = await axios.get(
                                    "https://" + authData.regionFloatIp + `:32800/rest/neteco/web/config/device/v1/children-list?conditionParams.curPage=0&conditionParams.mocTypes=60081&conditionParams.parentDn=${encodeURIComponent(parentDn)}&conditionParams.recordperpage=1`,
                                    {
                                        headers: {
                                            'roaRand': authData.roaRand,
                                            'Cookie': 'locale=de-de;bspsession=' + authData.accessToken + ';dp-session=' + authData.accessToken + '; Secure; HttpOnly'
                                        },
                                        httpsAgent: CONFIG.httpsAgent
                                    }
                                );
                        
                                log(`Wallbox-Einstellungen für ${parentDn}: ` + JSON.stringify(response.data), 'info');
                                const wallboxSettings = response.data.data[0];
                        
                                // Speichern der dnId
                                const dnId = wallboxSettings.dnId;
                                //setState('huawei-smart-charger.WallboxSettings.dnId', dnId, true);
                        
                                // Erstelle die Struktur für paramValues und andere Daten
                                const basePath = `huawei-smart-charger.WallboxSettings.${dnId}`;
                        
                                // Speichere alle Schlüssel von wallboxSettings in IoBroker, einschließlich paramValues
                                for (const key in wallboxSettings) {
                                    if (key === 'paramValues') {
                                        // Speziell für paramValues
                                        const paramValuesPath = `${basePath}.paramValues`;
                                        for (const paramKey in wallboxSettings.paramValues) {
                                            const paramValue = wallboxSettings.paramValues[paramKey];
                                            await setObject(`${paramValuesPath}.${paramKey}`, {
                                                type: 'state',
                                                common: {
                                                    name: `Parameter ${paramKey}`,
                                                    type: typeof paramValue,
                                                    role: 'info',
                                                    read: true,
                                                    write: WRITABLE_IDS.includes(parseInt(paramKey)) // Schreibbare IDs berücksichtigen
                                                },
                                                native: { id: paramKey, value: paramValue }
                                            });
                                            await setState(`${paramValuesPath}.${paramKey}`, paramValue, true);
                                        }
                                    } else {
                                        // Speichere alle anderen Daten in IoBroker
                                        await setObject(`${basePath}.${key}`, {
                                            type: 'state',
                                            common: {
                                                name: key,
                                                type: typeof wallboxSettings[key],
                                                role: 'info',
                                                read: true,
                                                write: false
                                            },
                                            native: { value: wallboxSettings[key] }
                                        });
                                        await setState(`${basePath}.${key}`, wallboxSettings[key], true);
                                    }
                                }
                        
                                // Nur beim ersten Mal die Wallbox-Konfigurationsinformationen abrufen
                                if (!getWallboxConfigInfo.calledWallboxSettings) {
                                    await getWallboxConfigInfo(dnId, wallboxSettings.paramValues);
                                    getWallboxConfigInfo.calledWallboxSettings = true;
                                }
                            } catch (error) {
                                log(`Fehler beim Abrufen der Wallbox-Einstellungen für ${parentDn}: ${error.message}`, 'info');
                            }
                        }
                        
                        // Wallbox-Konfigurationsinformationen abrufen und in den entsprechenden Pfaden anlegen
                        async function getWallboxConfigInfo(dnId, paramValues) {
                            if (!paramValues) {
                                log(`Keine Parameterwerte für dnId ${dnId} gefunden.`, 'info');
                                return;
                            }
                        
                            for (const id of Object.keys(paramValues)) {
                                try {
                                    const conditions = [{ queryAll: 0, signals: [id], dnId }];
                                    const response = await axios.post(
                                        "https://" + authData.regionFloatIp + ":32800/rest/neteco/web/homemgr/v1/device/get-config-info",
                                        JSON.stringify({ conditions }),
                                        {
                                            headers: {
                                                'roaRand': authData.roaRand,
                                                'Cookie': `locale=de-de;bspsession=${authData.accessToken};dp-session=${authData.accessToken}; Secure; HttpOnly`,
                                                "Content-Type": "application/json"
                                            },
                                            httpsAgent: CONFIG.httpsAgent
                                        }
                                    );
                        
                                    log(`Wallbox-Konfigurationsinformationen für ${dnId}, Signal ${id}: ` + JSON.stringify(response.data), 'debug');
                                    const wallboxConfigInfo = response.data;
                                    if (wallboxConfigInfo && wallboxConfigInfo[dnId] && wallboxConfigInfo[dnId][0]) {
                                        const { name, realValue, value, enumMap, unit } = wallboxConfigInfo[dnId][0];
                                        if (!name) continue;
                        
                                        // Sanitize the object ID, but not the display name
                                        const sanitizedKey = name
                                            .replace(/ä/g, 'ae')
                                            .replace(/ö/g, 'oe')
                                            .replace(/ü/g, 'ue')
                                            .replace(/Ä/g, 'Ae')
                                            .replace(/Ö/g, 'Oe')
                                            .replace(/Ü/g, 'Ue')
                                            .replace(/ß/g, 'ss')
                                            .replace(/\s+/g, '_')
                                            .replace(/[^\w\d_]/g, '');
                        
                        
                                        // Speichere in huawei-smart-charger.Wallbox.Values
                                        const key = sanitizedKey;
                                        const stateValue = enumMap && Object.keys(enumMap).length > 0 ? value : realValue;
                                        const valuePath = `huawei-smart-charger.Wallbox.Values.${key}`;
                                        const settingsPath = `huawei-smart-charger.Wallbox.Settings.${key}`;
                        
                                        // Objekt in Values erstellen
                                        await setObject(valuePath, {
                                            type: 'state',
                                            common: {
                                                name: name, // Keep the original name here
                                                type: typeof stateValue,
                                                role: 'info',
                                                read: true,
                                                write: WRITABLE_IDS.includes(parseInt(id)),
                                                unit: unit || undefined,
                                                states: Object.keys(enumMap).length > 0 ? enumMap : undefined,
                                                dnId: dnId // Speichern der dnId in common
                                            },
                                            native: wallboxConfigInfo[dnId][0]
                                        });
                                        await setState(valuePath, stateValue, true);
                        
                                        // Wenn das Objekt schreibbar ist, auch in Settings erstellen
                                        if (WRITABLE_IDS.includes(parseInt(id))) {
                                            await setObject(settingsPath, {
                                                type: 'state',
                                                common: {
                                                    name: name, // Keep the original name here
                                                    type: typeof stateValue,
                                                    role: 'info',
                                                    read: true,
                                                    write: true,
                                                    unit: unit || undefined,
                                                    states: Object.keys(enumMap).length > 0 ? enumMap : undefined,
                                                    dnId: dnId // Speichern der dnId in common
                                                },
                                                native: wallboxConfigInfo[dnId][0]
                                            });
                                            await setState(settingsPath, stateValue, true);
                                        }
                                    }
                                } catch (error) {
                                    log(`Fehler beim Abrufen der Wallbox-Konfigurationsinformationen für ${dnId}, Signal ${id}: ${error.message}`, 'error');
                                }
                            }
                        }
                        
                        
                        async function createAndSetObjects(basePath, data) {
                            if (!data) {
                                log(`Daten für ${basePath} sind null oder undefined.`, 'error');
                                return;
                            }
                        
                            for (const key in data) {
                                if (data.hasOwnProperty(key)) {
                                    const value = data[key];
                                    // Ersetze Leerzeichen im Objektnamen durch '_'
                                    const sanitizedKey = key.replace(/\s+/g, '_');
                                    const id = `${basePath}.${sanitizedKey}`;
                                    const objType = typeof value === 'object' && value !== null ? 'channel' : 'state';
                        
                                    log(`Versuche, Objekt ${id} zu erstellen. Typ: ${objType}, Wert: ${JSON.stringify(value)}`, 'info');
                        
                                    await setObject(id, {
                                        type: objType,
                                        common: {
                                            name: sanitizedKey,
                                            type: typeof value,
                                            role: objType === 'channel' ? 'folder' : 'state',
                                            read: true,
                                            write: WRITABLE_IDS.includes(parseInt(key))
                                        },
                                        native: typeof value === 'object' && value !== null ? value : { value: value }
                                    });
                        
                                    if (objType === 'state' && value !== null && value !== undefined) {
                                        await setState(id, value, true);
                                    } else if (objType === 'channel' && value !== null) {
                                        // Rekursiv verschachtelte Objekte verarbeiten
                                        await createAndSetObjects(id, value);
                                    }
                                }
                            }
                        }
                        
                        
                        // Aktualisierung des Verbindungsstatus
                        function updateConnectionState(isConnected) {
                            try {
                                setState('huawei-smart-charger.info.connection', isConnected, true);
                            } catch (error) {
                                log(`Fehler beim Aktualisieren des Verbindungsstatus: ${error.message}`, 'error');
                            }
                        }
                        
                        // Hauptlogik zur Authentifizierung und Datenabfrage
                        async function main() {
                            await authenticateAndScheduleRenewal();
                            if (!authData) return;
                        
                            await getUserDetailInfo();
                            await getServerInfo();
                            await getStationList();
                            await getWallboxInfo();
                            await getWallboxSettings();
                            await getChargeStatus();
                            
                        }
                        
                        // Lausche auf Änderungen der Settings und sende PUT-Anfrage an die API
                        on({ id: new RegExp('^huawei-smart-charger\\.Wallbox\\.Settings\\.[^.]+$'), change: 'ne' }, async (obj) => {
                            if (obj.state.ack) {
                                return; // Wenn die Änderung von der API bestätigt wurde, ignoriere sie
                            }
                        
                            const writableId = obj.native?.id;
                            if (!writableId || !WRITABLE_IDS.includes(writableId)) {
                                log(`Keine beschreibbare ID für ${obj.id} gefunden.`, 'warn');
                                return;
                            }
                        
                            try {
                                // Lese die dnId aus dem Objekt in common
                                const dnId = getObject(obj.id).common.dnId;
                                if (!authData || (authData && new Date().getTime() > authData.expiryTime)) {
                                    await authenticateAndScheduleRenewal();
                                }
                        
                                if (authData && dnId) {
                                    const requestData = {
                                        changeValues: [{ id: writableId, value: obj.state.val }],
                                        dnId: dnId
                                    };
                        
                                    log(`Sende Anfrage mit Daten: ${JSON.stringify(requestData)}`, 'debug');
                        
                                    const response = await axios.post(
                                        "https://" + authData.regionFloatIp + ":32800/rest/neteco/web/homemgr/v1/device/set-config-info",
                                        JSON.stringify(requestData),
                                        {
                                            headers: {
                                                'roaRand': authData.roaRand,
                                                'Cookie': `locale=de-de;bspsession=${authData.accessToken};dp-session=${authData.accessToken}; Secure; HttpOnly`,
                                                'Content-Type': 'application/json',
                                                'x-timezone-offset': '120',
                                                'client-info': '_manufacturer=iPhone;_model=iPhone;_os_ver=18.0.1;_os=iOS;_app_ver=24.6.102006;_package_name=com.huawei.smartpvms;appClientId=86366133-B8B5-41FA-8EB9-E5A64229E3D5',
                                                'x-requested-with': 'XMLHttpRequest',
                                                'User-Agent': 'iCleanPower/24.6.102006 (iPhone; iOS 18.0.1; Scale/3.00)',
                                                'Accept-Language': 'de-DE;q=1, en-DE;q=0.9, zh-Hans-DE;q=0.8',
                                                'Accept': '*/*'
                                            },
                                            httpsAgent: CONFIG.httpsAgent
                                        }
                                    );
                        
                                    log(`Antwort vom Server: ${JSON.stringify(response.data)}`, 'debug');
                                    if (response.data) {
                                        await setState(obj.id, obj.state.val, true);
                                    }
                                    await getWallboxInfo();
                                    await getWallboxSettings();
                                }
                            } catch (error) {
                                log(`Fehler beim Ändern des Werts für ${obj.id}: ${error.message}`, 'error');
                                if (error.response) {
                                    log(`Fehlerantwort vom Server: ${JSON.stringify(error.response.data)}`, 'error');
                                }
                            }
                        });
                        
                        // Monitor changes in WallboxSettings and WallboxInfo under paramValues
                        on({ id: new RegExp('^huawei-smart-charger\\.Wallbox(Settings|Info)\\.[^.]+\\.paramValues\\.[^.]+$'), change: 'ne' }, async (obj) => {
                            if (obj.state.ack) {
                                return; // If the change was confirmed by the API, ignore it
                            }
                        
                            try {
                                // Extract the parameter ID from the changed paramValues instance
                                const paramId = parseInt(obj.id.split('.').pop()); // Extract the parameter ID from the object path
                        
                                // Define a helper function to update corresponding objects
                                const updateObjects = async (basePath) => {
                                    getObjectView('system', 'state', { startkey: basePath, endkey: basePath + "\u9999" }, async (err, allObjects) => {
                                        if (err) {
                                            log(`Error fetching objects from ${basePath}: ${err.message}`, 'error');
                                            return;
                                        }
                        
                                        for (const obj of allObjects.rows) {
                                            const nativeId = obj.value.native?.id;
                                            if (nativeId === paramId) {
                                                // Update the state in the corresponding object
                                                const newValue = obj.state.val;
                                                await setState(obj.id, newValue, true);
                                                log(`Updated value in ${obj.id} to: ${newValue}`, 'info');
                                            }
                                        }
                                    });
                                };
                        
                                // Update the corresponding objects in Wallbox.Values and Wallbox.Settings
                                await updateObjects('huawei-smart-charger.Wallbox.Values.');
                                await updateObjects('huawei-smart-charger.Wallbox.Settings.');
                        
                            } catch (error) {
                                log(`Error while updating Wallbox.Values or Wallbox.Settings from paramValues change: ${error.message}`, 'error');
                            }
                        });
                        
                        // Ladestatus abfragen
                        async function getChargeStatus() {
                            try {
                                // Fetch the dnId from the IoBroker state
                                const dnId = getState('huawei-smart-charger.WallboxInfo.dnId').val;
                                if (!dnId) {
                                    log('dnId not found for getChargeStatus', 'warn');
                                    return;
                                }
                        
                                // Construct the request payload based on the provided curl example
                                const requestData = {
                                    gunNumber: 1, // Fixed value as per the example
                                    needRealTimeStatus: false, // This will be toggled based on the interval logic
                                    dnId: dnId
                                };
                        
                                // Perform the POST request
                                const response = await axios.post(
                                    "https://" + authData.regionFloatIp + ":32800/rest/neteco/web/homemgr/v1/charger/status/charge-status",
                                    JSON.stringify(requestData),
                                    {
                                        headers: {
                                            'roaRand': authData.roaRand,
                                            'Cookie': `locale=de-de;bspsession=${authData.accessToken};dp-session=${authData.accessToken}; Secure; HttpOnly`,
                                            'Content-Type': 'application/json',
                                            'x-timezone-offset': '120',
                                            'client-info': '_manufacturer=iPhone;_model=iPhone;_os_ver=18.0.1;_os=iOS;_app_ver=24.6.102006;_package_name=com.huawei.smartpvms;appClientId=86366133-B8B5-41FA-8EB9-E5A64229E3D5',
                                            'x-requested-with': 'XMLHttpRequest',
                                            'User-Agent': 'iCleanPower/24.6.102006 (iPhone; iOS 18.0.1; Scale/3.00)',
                                            'Accept-Language': 'de-DE;q=1, en-DE;q=0.9, zh-Hans-DE;q=0.8',
                                            'Accept': '*/*'
                                        },
                                        httpsAgent: CONFIG.httpsAgent
                                    }
                                );
                        
                                // Log the charge status response for testing
                                log(`Charge Status response: ${JSON.stringify(response.data)}`, 'info');
                        
                                // Update interval based on the charge status
                                if (response.data && response.data.chargeStatus !== undefined) {
                                    const status = response.data.chargeStatus;
                                    log(`Current charge status: ${status}`, 'info');
                                    scheduleIntervals(status); // Update intervals based on the charge status
                                } else {
                                    log(`Invalid response from getChargeStatus: ${JSON.stringify(response.data)}`, 'warn');
                                }
                        
                            } catch (error) {
                                log(`Fehler beim Abrufen des Ladestatus: ${error.message}`, 'error');
                                if (error.response) {
                                    log(`Fehlerantwort vom Server: ${JSON.stringify(error.response.data)}`, 'error');
                                }
                            }
                        }
                        
                        // Schedule intervals based on the charge status
                        function scheduleIntervals(chargeStatus) {
                            let intervalTime = 300000; // Default interval: 5 minutes
                            let needRealTimeStatus = false;
                        
                            // Define specific interval times based on the charge status
                            if ([3, 4, 7, 8].includes(chargeStatus)) {
                                intervalTime = 60000; // 30 seconds for these statuses
                                needRealTimeStatus = true; // Enable real-time status when charging or in related states
                            } else if ([1, 2, 6, 10, 11].includes(chargeStatus)) {
                                intervalTime = 180000; // 3 minutes for these statuses
                            }
                        
                            // Clear any existing intervals
                            clearInterval(infoInterval);
                            clearInterval(settingsInterval);
                        
                            // Schedule intervals with the appropriate time
                            infoInterval = setInterval(async () => {
                                await getWallboxInfo(needRealTimeStatus); // Fetch wallbox info at the set interval
                            }, intervalTime);
                        
                            settingsInterval = setInterval(async () => {
                                await getWallboxSettings(needRealTimeStatus); // Fetch wallbox settings at the set interval
                            }, intervalTime);
                        
                            log(`Scheduled intervals: ${intervalTime / 1000} seconds`, 'info');
                        }
                        
                        
                        // Initial call to getChargeStatus and start checking intervals
                        let infoInterval, settingsInterval;
                        async function checkChargeInterval() {
                            await getChargeStatus(); // Check the charge status initially and set intervals
                            setInterval(async () => {
                                await getChargeStatus(); // Re-check the charge status at regular intervals
                            }, CONFIG.interval);
                        }
                        
                        
                        
                        main();
                        
                        
                        P Offline
                        P Offline
                        Peguschwein
                        schrieb am zuletzt editiert von Peguschwein
                        #23

                        @stolly82 said in Huawei Wallbox - S Charger (7kw/h / 22kw/h) Adapter test:
                        Bin gerade auf diesen Artikel gestossen. Was soll da eingetragen werden ? Daten vom APP auf dem Smatphone ? Wo finde ich die appClientID ?

                          userName: 'MySUERNAME',
                          password: 'MyPASSWORD', 
                          grantType: 'password',
                          appClientId: '86366133-B8B5-41FA-8EB9-E5A64229E3E1'                                                 
                        

                        Gruss Peguschwein

                        Edit: Bin fündig geworden. werde mal testen

                        1 Antwort Letzte Antwort
                        0
                        • Dominic ReberD Offline
                          Dominic ReberD Offline
                          Dominic Reber
                          schrieb am zuletzt editiert von
                          #24

                          Hallo zusammen

                          Ich hab einen SUN2000-17K-MB0 plus S1 Speicher.
                          Nun möchte ich eine Wallbox installieren und natürlich liegt da der Huawei Smart Charger nah.

                          Ich steuere sonst alles über IoBroker inkl Überschuss.

                          Kann ich mit diesem Adapter hier OHNE EMMA die Wallbox selbst steuern (PV oder Normal-Laden starten/stoppen)?

                          Danke

                          B 1 Antwort Letzte Antwort
                          0
                          • Dominic ReberD Dominic Reber

                            Hallo zusammen

                            Ich hab einen SUN2000-17K-MB0 plus S1 Speicher.
                            Nun möchte ich eine Wallbox installieren und natürlich liegt da der Huawei Smart Charger nah.

                            Ich steuere sonst alles über IoBroker inkl Überschuss.

                            Kann ich mit diesem Adapter hier OHNE EMMA die Wallbox selbst steuern (PV oder Normal-Laden starten/stoppen)?

                            Danke

                            B Offline
                            B Offline
                            baerengraben
                            schrieb am zuletzt editiert von baerengraben
                            #25

                            @dominic-reber Im aktuellen Stand kann man mit dem Script viele Infos von der Wallbox lesen. Schreiben (setzen) funktioniert bei mir nur für den Arbeitsmodus (PV-Überschuss / Manuell laden). Aber man kann bis jetzt nicht die Ladung selber starten/stoppen.

                            @stolly82 Tatsächlich wäre es super, wenn nebst den Werten in Wallbox>Settings auch noch das Laden selber gestartet/gestoppt werden könnte. Könntest du dies noch im Script implementieren?

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


                            Support us

                            ioBroker
                            Community Adapters
                            Donate

                            901

                            Online

                            32.5k

                            Benutzer

                            81.8k

                            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