Homey Community Forum

Wallbox Pulsar plus charger lock/unlock

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.

2 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;
}
1 Like

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;
}