Wallbox Pulsar plus charger lock/unlock pause/resume

I was considering writing a complete app and I still might when I have the time.

In the mean time I’ve written a homeyscript that allows you to lock/unlock your wallbox electric car charger ( wallbox.com ).
I just post it here as there is virtually no documentation available and wallbox’s are being sold more and more now here in the Netherlands.
Most frustrating part was to connect my car to the wallbox, open the app, wait for a connect, then open the charger part and unlock it. Took way to much time.
Now I have setup a virtual device called “laadpaal” ( charger ). Tell Google to turn it on or off ( making it unlock or lock ) and takes 3 seconds.

If anyone is interested, let me know.

btw… I should be able to add pause/resume to charging and have variables filled with current power usage if anyone needs it.

8 Likes

So, through facebook I had a couple of requests to share what I’ve done.
To run this script you need your login information to your Wallbox account ( https://my.wallbox.com ) and the charger ID you want to lock or unlock.
Getting the ID is simple. Just login to my.wallbox.com and click on your charger. When you are on the page with all the details of your charger you can read the ID from the URL in your browser. It’s the number after the last slash.
wallbox_charger_nr

Go to homeyscript and create a new script. Call it e.g. wallbox ( I did ).
Copy and paste the code below in your new script and enter the details in the top three lines of the code.
Save it.

In my case I then created a virtual device called “laadpaal”.
afbeelding

And two flows for when turned on or off ( unlock or lock ).
afbeelding

To unlock your charger, run the wallbox script with argument unlock.
afbeelding

To lock your charger, run the wallbox script with argument lock.
afbeelding

If you have Google connected to your Homey, you can simply say zet laadpaal aan or set laadpaal uit to unlock or lock the charger.

Code :

const username = '<your username (usually email address)';
const password = '<your password>';
const MYCHARGERID = 000000; // ID of your charger

const BASEURL = "https://api.wall-box.com/";
const URL_AUTHENTICATION = 'auth/token/user';
const URL_UNLOCKCHARGER = 'v2/charger/';

var token = '';
var unlocked = { 'locked': 0 };
var locked = { 'locked': 1 };


/**
 * Get JWT Token from wallbox using login and password
 */
async function connectToWallbox() {
  let connect = await fetch( BASEURL + URL_AUTHENTICATION, {
    headers: {
      'Authorization': 'Basic ' + Buffer.from( username + ":" + password ).toString( 'base64' ),
      'Accept': 'application/json, text/plain, */*',
      'Content-Type': 'application/json;charset=utf-8',
    }
  } ).then( response => response.json() );
  return connect.jwt;
}

/**
 * Unlock wallbox function with token from Connect function
 */
async function unlockWallbox( token ) {
  let unlock = await fetch( BASEURL + URL_UNLOCKCHARGER + MYCHARGERID, {

    method: 'PUT',
    headers: {
      'Authorization': 'Bearer ' + token,
      'Accept': 'application/json, text/plain, */*',
      'Content-Type': 'application/json;charset=utf-8',

    },
    body: JSON.stringify( unlocked )
  } ).then( response => response.json() );
  if ( unlock.code === 200 ) {
    return false;
  }
  return true;
}

/**
 * Lock wallbox function with token from Connect function
 */
async function lockWallbox(token) {
  let lock = await fetch( BASEURL + URL_UNLOCKCHARGER + MYCHARGERID, {

    method: 'PUT',
    headers: {
      'Authorization': 'Bearer ' + token,
      'Accept': 'application/json, text/plain, */*',
      'Content-Type': 'application/json;charset=utf-8',

    },
    body: JSON.stringify(locked)
  } ).then( response => response.json() );
  if ( lock.code === 200 ) {
    return false;
  }
  return true;
}

// Make sure this script works with 1 single argument
if ( typeof args[0] !== 'string' ) {
  throw new Error( 'Script must be run from a flow with a string variable' );
}


switch ( args[0] ) {
  case "unlock":
    token = await connectToWallbox();
    result = await unlockWallbox( token );
    // Optional. You can leave the next 3 lines out and place them in a flow
    if ( result === true ) {
      say( 'Wallbox is ontgrendeld' );
    }
    break;
  case "lock":
    token = await connectToWallbox();
    result = await lockWallbox( token );
    // Optional. You can leave the next 3 lines out and place them in a flow
    if ( result === true ) {
      say( 'Wallbox is vergrendeld' );
    }
    break;
}
4 Likes

Nice work, I will be getting a Wallbox Pulsar Plus and an EV within 6 months or so and love this already :smiley:

Hi! I share your frustration on the no documentation part on Wallbox Pulsar
Do you have a working script with pause and resume? That would really solve a lot of issues for me.
I started on programming the resume and pause function on your script. But it does not work. Maybe you can help me?

I gathered the URL-info from this program:

Here is what i did yesterday. Mark that I do not have any experience in programming
REMINDER: This code does not work:

Code:

const BASEURL = "https://api.wall-box.com/";
const URL_AUTHENTICATION = 'auth/token/user';
const URL_UNLOCKCHARGER = 'v2/charger/';

// Added for pause and resume
const URL_PAUSECHARGE = 'v3/chargers/';
const URL_REMOTE_ACTION = '/remote-action/';
const URL_CHARGERSTATUS = 'chargers/status/';


var token = '';
var unlocked = { 'locked': 0 };
var locked = { 'locked': 1 };

// Added by me
var pause = { 'action': 2 };
var resume = { 'action': 1 };
var status = '';

/**
 * Get JWT Token from wallbox using login and password
 */
async function connectToWallbox() {
  let connect = await fetch( BASEURL + URL_AUTHENTICATION, {
    headers: {
      'Authorization': 'Basic ' + Buffer.from( username + ":" + password ).toString( 'base64' ),
      'Accept': 'application/json, text/plain, */*',
      'Content-Type': 'application/json;charset=utf-8',
    }
  } ).then( response => response.json() );
  return connect.jwt;
}

/**
 * Get Charge status. I think we need it to make resume work. This part does not work
 */
async function chargerStatusWallbox(token) {
  let chargerstatus = await fetch( BASEURL + URL_CHARGERSTATUS + MYCHARGERID, {

    method: 'GET',
    headers: {
      'Authorization': 'Bearer ' + token,
      'Accept': 'application/json, text/plain, */*',
      'Content-Type': 'application/json;charset=utf-8',
  
  } 
  body: JSON.stringify( status )
  } ).then( response2 => response2.json() );
  if ( unlock.code === 200 ) {
    return false;
  }
  return true;
}




/**
 * Unlock wallbox function with token from Connect function
 */
async function unlockWallbox(token: string) {
  let unlock = await fetch( BASEURL + URL_UNLOCKCHARGER + MYCHARGERID, {

    method: 'PUT',
    headers: {
      'Authorization': 'Bearer ' + token,
      'Accept': 'application/json, text/plain, */*',
      'Content-Type': 'application/json;charset=utf-8',

    },
    body: JSON.stringify( unlocked )
  } ).then( response => response.json() );
  if ( unlock.code === 200 ) {
    return false;
  }
  return true;
}

/**
 * Lock wallbox function with token from Connect function
 */
async function lockWallbox(token) {
  let lock = await fetch( BASEURL + URL_UNLOCKCHARGER + MYCHARGERID, {

    method: 'PUT',
    headers: {
      'Authorization': 'Bearer ' + token,
      'Accept': 'application/json, text/plain, */*',
      'Content-Type': 'application/json;charset=utf-8',

    },
    body: JSON.stringify(locked)
  } ).then( response => response.json() );
  if ( lock.code === 200 ) {
    return false;
  }
  return true;
}

/** 
 * Pause charging on wallbox with token from Connect function, 
 */
async function pauseWallbox(token) {
  let pause = await fetch( BASEURL + URL_PAUSECHARGE + MYCHARGERID + URL_REMOTE_ACTION, {

    method: 'PUT',
    headers: {
      'Authorization': 'Bearer ' + token,
      'Accept': 'application/json, text/plain, */*',
      'Content-Type': 'application/json;charset=utf-8',

    },
    body: JSON.stringify(pause)
  } ).then( response => response.json() );
  if ( pause.code === 200 ) {
    return false;
  }
  return true;
}

/** Resume charging on wallbox with token from Connect function
 */
async function resumeWallbox(token) {
  let resume = await fetch( BASEURL + URL_PAUSECHARGE + MYCHARGERID + URL_REMOTE_ACTION, {

    method: 'PUT',
    headers: {
      'Authorization': 'Bearer ' + token,
      'Accept': 'application/json, text/plain, */*',
      'Content-Type': 'application/json;charset=utf-8',

    },
    body: JSON.stringify(resume)
  } ).then( response => response.json() );
  if ( resume.code === 200 ) {
    return false;
  }
  return true;
}

// Make sure this script works with 1 single argument
if ( typeof args[0] !== 'string' ) {
  throw new Error( 'Script must be run from a flow with a string variable' );
}


switch ( args[0] ) {
  case "unlock":
    token = await connectToWallbox();
    result = await unlockWallbox( token );
    // Optional. You can leave the next 3 lines out and place them in a flow
    if ( result === true ) {
      say( 'Wallbox is unlocked' );
    }
    break;
  case "lock":
    token = await connectToWallbox();
    result = await lockWallbox( token );
    // Optional. You can leave the next 3 lines out and place them in a flow
    if ( result === true ) {
      say( 'Wallbox is locked' );
    }
    break;
// LAGT til av meg
  case "pause":
    token = await connectToWallbox();
    status = await chargerStatusWallbox( token );
    result = await pauseWallbox( token );
    // Optional. You can leave the next 3 lines out and place them in a flow
    if ( result === true ) {
      say( 'Wallbox is paused' );
    }
    break;
  case "resume":
    token = await connectToWallbox();
    status = await chargerStatusWallbox( token );
    result = await resumeWallbox( token );
    // Optional. You can leave the next 3 lines out and place them in a flow
    if ( result === true ) {
      say( 'Wallbox is resumed' );
    }
    break;
}

Hi!
Sorry for the late response! For some reason I didn’t receive a notification while I do have them all on…
Will have a look for you later today!

This is an addition to the first script to handle pause and resume.

const username = '<your username (usually email address)';
const password = '<your password>';
const MYCHARGERID = 000000; // ID of your charger
const BASEURL = "https://api.wall-box.com/";
const URL_AUTHENTICATION = 'auth/token/user';
const URL_UNLOCKCHARGER = 'v2/charger/';
const URL_PAUSECHARGER = 'v3/chargers/';
const URL_PAUSECHARGER_ACTION = '/remote-action';

var token = '';
var unlocked = { 'locked': 0 };
var locked = { 'locked': 1 };
var resume = { 'action': 1 };
var pause = { 'action': 2 };


/**
 * Get JWT Token from wallbox using login and password
 */
async function connectToWallbox() {
  let connect = await fetch(BASEURL + URL_AUTHENTICATION, {
    headers: {
      'Authorization': 'Basic ' + Buffer.from(username + ":" + password).toString('base64'),
      'Accept': 'application/json, text/plain, */*',
      'Content-Type': 'application/json;charset=utf-8',
    }
  }).then(response => response.json());
  return connect.jwt;
}

/**
 * Unlock wallbox function with token from Connect function
 */
async function unlockWallbox(token) {
  let unlock = await fetch(BASEURL + URL_UNLOCKCHARGER + MYCHARGERID, {

    method: 'PUT',
    headers: {
      'Authorization': 'Bearer ' + token,
      'Accept': 'application/json, text/plain, */*',
      'Content-Type': 'application/json;charset=utf-8',

    },
    body: JSON.stringify(unlocked)
  }).then(response => response.json());
  if (unlock.error === true) {
    return unlock.message;
  }
  return true;
}

/**
 * Lock wallbox function with token from Connect function
 */
async function lockWallbox(token) {
  let lock = await fetch(BASEURL + URL_UNLOCKCHARGER + MYCHARGERID, {

    method: 'PUT',
    headers: {
      'Authorization': 'Bearer ' + token,
      'Accept': 'application/json, text/plain, */*',
      'Content-Type': 'application/json;charset=utf-8',

    },
    body: JSON.stringify(locked)
  }).then(response => response.json());
  if (lock.error === true) {
    return lock.message;
  }
  return true;
}

/**
 * Resume wallbox function with token from Connect function
 */
async function resumeWallbox(token) {
  let wbResume = await fetch(BASEURL + URL_PAUSECHARGER + MYCHARGERID + URL_PAUSECHARGER_ACTION, {

    method: 'POST',
    headers: {
      'Authorization': 'Bearer ' + token,
      'Accept': 'application/json, text/plain, */*',
      'Content-Type': 'application/json;charset=utf-8',

    },
    body: JSON.stringify(resume)
  }).then(response => response.json());
  if ( wbResume.error === true ) {
    return wbResume.message;
  }
  return true;
}

/**
 * Pause wallbox function with token from Connect function
 */
async function pauseWallbox(token) {
  let wbPause = await fetch(BASEURL + URL_PAUSECHARGER + MYCHARGERID + URL_PAUSECHARGER_ACTION, {

    method: 'POST',
    headers: {
      'Authorization': 'Bearer ' + token,
      'Accept': 'application/json, text/plain, */*',
      'Content-Type': 'application/json;charset=utf-8',

    },
    body: JSON.stringify(pause)
  }).then(response => response.json());
  if ( wbPause.error === true ) {
    return wbPause.message;
  }
  return true;
}

// Make sure this script works with 1 single argument
if (typeof args[0] !== 'string') {
  throw new Error('Script must be run from a flow with a string variable');
}


switch (args[0]) {
  case "unlock":
    token = await connectToWallbox();
    result = await unlockWallbox(token);
    // Optional. You can leave the next 3 lines out and place them in a flow
    if (result === true) {
      say('Wallbox is ontgrendeld');
    } else say( result );
    break;
  case "lock":
    token = await connectToWallbox();
    result = await lockWallbox(token);
    // Optional. You can leave the next 3 lines out and place them in a flow
    if (result === true) {
      say('Wallbox is vergrendeld');
    } else say( result );
    break;
  case "pause":
    token = await connectToWallbox();
    result = await pauseWallbox(token);
    // Optional. You can leave the next 3 lines out and place them in a flow
    if (result === true) {
      say('Wallbox is gepauzeerd');
    } else say( result );
    break;
  case "resume":
    token = await connectToWallbox();
    result = await resumeWallbox(token);
    // Optional. You can leave the next 3 lines out and place them in a flow
    if (result === true) {
      say('Wallbox is weer an het laden');
    } else say( result );
    break;
}
3 Likes

Hi Sen-Sai
Thank you so much for this script. It works flawlessly! Late response is better than none :smile:
I see that I was “closer” to a solution that I thought I was :smile:

Now I can do this in a flow

  • Default at locked mode. Wallbox does not start charging
  • Use unlock when price is low
  • Use pause when the price is high after unlock
  • Use resume when price is low again

Thanks! Good to hear!

Hi, i would like to have wallbox pulsar plus app. I would donate some money to have it :blush:

2 Likes

With the help of Sen-Sai’s script I made an app, see youtube https://www.youtube.com/watch?v=NtlvPnDq5qw
The code is available on GitHub: https://github.com/zekitez/WandDeuze and the app in Google play.

Hello,
J‘ai pas encore réussi à créer un périphérique virtuel (je suis très débutant) mais j’ai une installation solaire et ce serait génial si des variables pouvaient géré la puissance de la Wallbox.
Est-ce que tu as réussi à créer quelques choses?

Hello,
Merci pour cette appli, elle marche du tonnerre!! :ok_hand:t3:

If you could please keep the conversation in English as much as possible, then more people will be able to participate and help you. If you would rather not or can’t communicate in English then please check out Non-English boards/categories:

Français (French)

Hello,
I haven’t managed to create a virtual device yet (I’m a very beginner) but I have a solar installation and it would be great if variables could manage the power of the Wallbox.
Did you manage to create a few things?

Hi Sen-Sai,

Thanks for all your work!
I’ve been struggling to get the ‘argument’s’.
How are they added to my tags?

I’m a pro at copy-and-pasting everything you’ve done, but that’s as far as my knowledge goes :slight_smile:
Nogmaals dank!

Hi!

When you look at the second post, with the screenshots, there’s one of a flow where I’ve added a homeyscript card that is called something like run script with arguments. That’s the one to use.
Or did you mean something else?

Hi!

Sorry no I have not. The arguments currently only have to do with lock and unlock, pause and resume.
But since you have asked, I’ll have a look when I have some time to add the power outage.

2 Likes

I tried to manage this, But is too much for me. I wait for an app. Can I donate?
Best regards Adri

Does anyone know if there will be an app for this?

1 Like

Hi again! It would have been really nice to been able to adjust the power outage. @Ze_Kitez have documented this quite well in the github-link GitHub - zekitez/WandDeuze: Android app WandDeuze communicates with your "Wallbox (Pulsar (Plus))" via Wifi only.

I tried to program some one this, but not sure how i get the return variable back (power outage) to use it in a flow