[APP][Pro] Nissan Leaf - Switch to smarter driving

Awesome - thanks for the quick fix!

I did not fix anything :grin: I guess @Jonas_Enge implemented a fix, but he is probably still looking for someone to take over the project.

Looks like it stopped working again :smirking_face:

I’m not able to log in to the Nissan Connect Android app either, so maybe this time it’s a Nissan server problem?

Update:

Translated from Nissan Support: “A temporary problem has occurred with the Nissan EV app. We are currently fixing the error and waiting for feedback from the technical department.”

Update: working for me again now

Is it possible to get this work fot after 2019 models also. I´m willing to donate 20€.

I also want to make a donation for a Homey Nissan Connect app.

Any update: Tried to connect my Leaf (dec 2020), but unfortunately an error too.

The app works fine, but your car is not supported. Only cars made before may 2019 is supported

Ok Thanks, any outlook to have the 2020- model supported?

Since two days the homey Nissan app is not fetching data anymore. Are there more people with this problem?

Looks like Nissan updated their API. New API endpoint URL · Issue #57 · joeshaw/carwings · GitHub

Has anyone taken over this project from @Jonas_Enge and can make the necessary updates?

All ok after the last app update

Winter is coming, so I took matters into my own hands and wrote a Homeyscript that starts the Climate Controls. This means you finally get the flow card that this app is lacking. Tested October 2025 for Europe. Interested to see if this works for all of you guys….

In order for this to work you will have to manually encrypt your Nissan password to the AES standard Nissan uses. See the comments at the top of the code with for URL and the needed parameters.

// Start Nissan Leaf Climate Control
//Nissan uses AES encryption of your personal password in order to authenticate you.
//This code needs your encrypted password to work. Go to: 
//https://www.devglan.com/online-tools/aes-encryption-decryption
//Text to encrypt= your password, Cipher Mode:CBC, PKCS5Padding, IV= xaX4ui2PLnwqcc74, key Size= 256, secret= H9YsaE6mr3jBEsAaLC4EJRjn9VXEtTzV

const username = "USERNAME"; //<---Your e-mail
const encryptedPassword = "ENCRYPTED_PASSWORD"; //<---Get this from URL
const regionCode = "NE"; 
// Europe=NE, USA=NNA, Canda=NCI, Australia=NMA, Japan=NML
const baseUrl = "https://gdcportalgw.its-mo.com/api_v250205_NE/gdc/";
const initial_app_str = "9s5rfKVuMrT03RtzajWNcA";

// HTTP POST helper
async function post(endpoint, params) {
  const url = baseUrl + endpoint;
  const body = new URLSearchParams(params);
  const res = await fetch(url, {
    method: "POST",
    headers: {
      "User-Agent": "Mozilla/5.0",
      "Content-Type": "application/x-www-form-urlencoded"
    },
    body: body.toString()
  });

  const text = await res.text();
  try {
    return { ok: true, json: JSON.parse(text), raw: text };
  } catch {
    return { ok: false, error: "Failed to parse JSON", raw: text };
  }
}

async function startClimate() {
  // Login
  const login = await post("UserLoginRequest.php", {
    initial_app_str,
    UserId: username,
    Password: encryptedPassword,
    RegionCode: regionCode
  });
  if (!login.ok || !login.json) return `❌ Login failed: ${login.raw || login.error}`;
  const resp = login.json;

  // Extract VIN, session, timezone
  const car = resp.VehicleInfoList?.vehicleInfo?.find(v => v.custom_sessionid);
  if (!car) return "❌ No valid vehicle session found in login response.";
  const vin = car.vin;
  const session = car.custom_sessionid;
  const tz = resp.CustomerInfo?.Timezone || "Europe/Oslo";

  // Wake-up request (BatteryStatusCheckRequest)
  const wakeup = await post("BatteryStatusCheckRequest.php", {
    RegionCode: regionCode,
    VIN: vin,
    custom_sessionid: session,
    tz: tz
  });
  if (!wakeup.ok || !wakeup.json) return `⚠️ Wake-up failed: ${wakeup.raw || wakeup.error}`;
  const resultKey = wakeup.json?.resultKey;
  if (!resultKey) return `⚠️ Wake-up returned no resultKey: ${wakeup.raw}`;

  // Simple async wait (non-blocking)
async function sleep(ms) {
  const end = Date.now() + ms;
  while (Date.now() < end) await Promise.resolve(); // yield event loop
}

// Poll until wake-up completes (CheckUpdate)
let awake = false;
  for (let i = 0; i < 8; i++) {
    await wait(5000); // ✅ HomeyScript built-in wait (milliseconds)
    const check = await post("BatteryStatusCheckResultRequest.php", {
      RegionCode: regionCode,
      VIN: vin,
      custom_sessionid: session,
      tz: tz,
      resultKey: resultKey
    });
    if (check.ok && check.json && check.json.responseFlag === "1") {
      awake = true;
      break;
    }
  }
  if (!awake) return `⚠️ Vehicle did not respond to wake-up in time (VIN: ${vin})`;


  // Send the AC start command
  const acReq = await post("ACRemoteRequest.php", {
    RegionCode: regionCode,
    VIN: vin,
    custom_sessionid: session,
    tz: tz
  });
  if (!acReq.ok || !acReq.json) return `❌ AC request failed: ${acReq.raw || acReq.error}`;
  if (acReq.json.ErrorCode) return `⚠️ AC API error: ${acReq.json.ErrorCode} - ${acReq.json.ErrorMessage}`;

  return `✅ Climate start command sent successfully`;
}

// Run the flow
return await startClimate();

EDIT: Today I did not get a response in time from the car and had to run the flow card twice in order to start the climate control. I learned that Homeyscript have a max run time of 30sec, which is a bit small when talking to Nissan….So I have now made a flow which separates the “poll until wake-up complete” into a separate flow card which can be run as many times as I’d like. So I’m testing out a setup which allow for maximum 40 seconds wait (excluding the login time) before exiting the test. If someone is interested, please reply

2 Likes

Great work, unfortunately I got the message that vehicle did not respond in time. Probably your splitted script would solve that. Can you share it?

UPDATE: It seems that nissan has introduced case sensitive username, so make sure that you use the same as when first registered.

Anyone else having issues with the app? Has Nissan changed the api again?

@Jonas_Enge Could it be that the countrycode now needs to be hardcoded as done in the dartnissanconnect here: Use hardcoded realm · Tobiaswk/dartnissanconnect@0cabf82 · GitHub

1 Like