Umstellung auf myHyundai-APP, fhempy (Kia_Hyundai-Modul) funktioniert nicht mehr

Begonnen von Guzzi-Charlie, 20 Oktober 2025, 11:36:58

Vorheriges Thema - Nächstes Thema

RPort

Für Hyundai hat das bei mir nicht funktioniert.
Haben sich vtl. für Hyundai die Hosts geändert?
Kann jemand bestätigen, dass es für Hyundai noch funktioniert und ggf. wie

optimizer

Zitat von: Rewe2000 am 21 Februar 2026, 20:06:49Wenn es Probleme macht den Code dem PDF zu entnehmen, kurze Nachricht und ich stelle diesen nochmals als Code hier ein.

Das würde anderen sicher helfen.

Ich habe das Script (mit Hilfe von Claude.ai) etwas umgebaut:
- für ältere Kia-Fahrzeuge (z.B. eNiro) ist die JSON Struktur etwas anders.
- es kommt oft vor dass die Antwort mit Bad Request endet. Daher gibt es einen 3-maligen Retry.
Auf Repository https://github.com/PierreLevres/Kuvork.git zu wechseln (anstatt https://github.com/Hacksore/bluelinky ) war bei mir der entscheidende Hinweis.
Hier mein Script:
#!/usr/bin/env node

// --- Imports ---
const fs = require('fs');
const path = require('path');
const { BlueLinky } = require('./dist/index.cjs');
const MQTT = require("async-mqtt");

// --- Konfiguration laden ---
const configPath = "/home/pi/.config/kia/credentials.json";
let config;

try {
  const raw = fs.readFileSync(configPath, 'utf8');
  config = JSON.parse(raw);
} catch (err) {
  console.error(`Fehler beim Laden der Config-Datei (${configPath}): ${err.message}`);
  process.exit(1);
}

// --- Hilfsfunktionen ---

// Zahlenwerte sicher abfragen
function safeValue(value) {
  return (typeof value === "number" && !isNaN(value)) ? value : null;
}

// Ladestecker 0/1/2 in Textrückmeldung wandeln
function connectorToText(value) {
  if (value === 0) return "nicht angeschlossen";
  if (value >= 1) return "gesteckt";  // 2=AC, 1=DC, beide sind "gesteckt"
  return "unbekannt";
}

// Hilfsfunktion für Datum/Zeit-Format
function getFormattedDateTime() {
  const now = new Date();
  const year = now.getFullYear();
  const month = String(now.getMonth() + 1).padStart(2, '0');
  const day = String(now.getDate()).padStart(2, '0');
  const hours = String(now.getHours()).padStart(2, '0');
  const minutes = String(now.getMinutes()).padStart(2, '0');
  const seconds = String(now.getSeconds()).padStart(2, '0');
  return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}

// --- Retry-Konfiguration ---
let retryCount = 0;
const MAX_RETRIES = 2;
const RETRY_DELAY = 10000; // 10 Sekunden

// --- Verbindungsversuch ---
async function attemptConnection() {
  return new Promise((resolve, reject) => {
    console.log(`Verbindungsversuch ${retryCount + 1}/${MAX_RETRIES + 1}...`);

    const client = new BlueLinky({
      username: config.api.username,
      password: config.api.password,
      brand: 'kia',
      region: 'EU',
      pin: config.api.pin,
      language: 'de'
    });

    let readyReceived = false;
    const timeout = setTimeout(() => {
      if (!readyReceived) {
        console.log('⚠️  Timeout - kein Ready-Event empfangen');
        reject(new Error('Timeout waiting for ready event'));
      }
    }, 30000); // 30 Sekunden Timeout

    client.on('ready', async () => {
      readyReceived = true;
      clearTimeout(timeout);
      console.log('✅ Ready-Event empfangen');

      try {
        await handleVehicleData(client);
        resolve();
      } catch (err) {
        reject(err);
      }
    });

    client.on('error', (err) => {
      if (err.path && err.path.includes('notifications/register')) {
        console.log('⚠️  Push-Notification fehlgeschlagen (ignoriert)');
        return;
      }

      console.error('❌ Login-Fehler:', err.message);
      clearTimeout(timeout);
      reject(err);
    });
  });
}

// --- Fahrzeugdaten verarbeiten ---
async function handleVehicleData(client) {
  const vehicle = client.getVehicle(config.api.vin);

  console.log('Hole Fahrzeugdaten...');

  const status = await vehicle.status({ parsed: false, refresh: true });
  const location = await vehicle.location();
  const odometer = await vehicle.odometer();

  // Einzelwerte mit Sicherheitsprüfung
  const odo = safeValue(odometer?.value);
  const ran = safeValue(status?.evStatus?.drvDistance?.[0]?.rangeByFuel?.evModeRange?.value);
  const soc = safeValue(status?.evStatus?.batteryStatus);
  const typ = connectorToText(safeValue(status?.evStatus?.batteryPlugin));
  const bat = safeValue(status?.battery?.batSoc);
  const lat = safeValue(location?.latitude);
  const lon = safeValue(location?.longitude);
  const carLocked = status?.doorLock;
  const batteryCharge = status?.evStatus?.batteryCharge;

  // Ausgabe
  console.log("odometer (Kilometerstand):", odo);
  console.log("range (Reichweite):", ran);
  console.log("SOC (Batterieladestand):", soc);
  console.log("chargingPlug (Ladestecker):", typ);
  console.log("battery12V_SOC (Ladestand 12V Batterie):", bat);
  console.log("Locked (Fahrzeug verschlossen):", carLocked);
  console.log("latitude (Breitengrad):", lat);
  console.log("longitude (Längengrad):", lon);
  console.log("batteryCharge (Battery wird geladen):", batteryCharge);
  console.log("lastUpdate (Abfragedatum):", getFormattedDateTime());

  // Validierung: Nur wenn wichtige Daten vorhanden sind
  if (typeof odo !== "number" || isNaN(odo) || typeof soc !== "number" || isNaN(soc)) {
    throw new Error("Unvollständige Daten empfangen (Odometer oder SOC fehlt)");
  }

  // An MQTT senden
  const mqttClient = await MQTT.connectAsync(config.mqtt.host, {
    username: config.mqtt.username,
    password: config.mqtt.password
  });

  console.log("Sending to MQTT server");

  const topic = `BluelinkCarStatus/${config.api.vin}`;
  await mqttClient.publish(
    topic,
    JSON.stringify({
      odometer: Math.round(odo),
      range: ran,
      SOC: soc,
      chargingPlug: typ,
      battery12V_SOC: bat,
      locked: carLocked,
      latitude: lat,
      longitude: lon,
      batteryCharge: batteryCharge,
      state: `Ladekabel: ${typ} SOC: ${soc}% range: ${ran}`,
      lastUpdate: getFormattedDateTime()
    }),
    { retain: true, qos: 1 }
  );

  await mqttClient.end();
  console.log("✅ MQTT call Done");
}

// --- Fehler an MQTT senden ---
async function sendErrorToMQTT(errorMessage) {
  try {
    const mqttClient = await MQTT.connectAsync(config.mqtt.host, {
      username: config.mqtt.username,
      password: config.mqtt.password
    });

    await mqttClient.publish(
      `BluelinkCarStatus/${config.api.vin}`,
      JSON.stringify({
        state: `Fehler: ${errorMessage}`,
        lastUpdate: getFormattedDateTime()
      }),
      { retain: true, qos: 1 }
    );

    await mqttClient.end();
    console.log('Fehlerstatus an MQTT gesendet');
  } catch (mqttErr) {
    console.error('❌ Konnte Fehler nicht an MQTT senden:', mqttErr.message);
  }
}

// --- Haupt-Ausführung mit Retry ---
(async function main() {
  console.log('=== Kia UVO zu FHEM/MQTT Bridge ===');

  while (retryCount <= MAX_RETRIES) {
    try {
      await attemptConnection();
      console.log('\n✅ Erfolgreich abgeschlossen');
      process.exit(0);

    } catch (err) {
      console.error(`\n❌ Versuch ${retryCount + 1} fehlgeschlagen:`, err.message);

      retryCount++;

      if (retryCount <= MAX_RETRIES) {
        console.log(`⏳ Warte ${RETRY_DELAY/1000} Sekunden vor erneutem Versuch...\n`);
        await new Promise(resolve => setTimeout(resolve, RETRY_DELAY));
      } else {
        console.error(`\n❌ Maximale Anzahl an Versuchen erreicht (${MAX_RETRIES + 1})`);

        // Fehler an MQTT senden
        await sendErrorToMQTT(`Fehler nach ${MAX_RETRIES + 1} Versuchen: ${err.message}`);

        process.exit(1);
      }
    }
  }
})();



optimizer

Zitat von: RPort am 22 Februar 2026, 11:16:52Für Hyundai hat das bei mir nicht funktioniert.
Haben sich vtl. für Hyundai die Hosts geändert?
Kann jemand bestätigen, dass es für Hyundai noch funktioniert und ggf. wie
Du müstest auf alle Fälle im Script brand: 'kia' auf 'hyundai' ändern und ausprobieren. Bin mir aber nicht sicher, ob Hyundai die gleichen Anmelde-Server hat.