Wallbox Pulsar plus charger lock/unlock pause/resume

I would have thought I’d be able to have had a look by now, but alas. Can’t promise anything, but I’ll put it in my agenda for this weekend…

1 Like

No need to rush :smile: Maybe you could extraxt the monthly usage data i kwh. That is probably easy task for you, but still.

That should be possible with the Power by the Hour app.

1 Like

The reply message on changing the amps contains:

"maxChgCurrent":15,"maxAvailableCurrent":20,"maxChargingCurrent":12  but also
"totalSessions":21,"chargingTime":"239647","totalEnergy":"141749","totalMidEnergy":"0","energyUnit":"kWh"

I will check if one can extract the kWh per session or per month, some how, but these values seem to be the totals since the wallbox was installed.

Examples of ‘message’ are documented in WallboxPulsarPlus.java
The Android app can log the replies and it looks like:

33787 ms : WallboxPulsarPlus Debug: setWallboxMaxChargingCurrent current:12
35205 ms : WallboxPulsarPlus Debug: ResponseCode: 200 msg: OK
35209 ms : WallboxPulsarPlus Debug: setWallboxMaxChargingCurrent response: {"data":{"chargerData":{"id":12345,"uid":"...","serialNumber":"12345","name":"PulsarPlus SN 97321","group":111111,"chargerType":"PulsarPlus","softwareVersion":"5.5.10","status":179,"ocppConnectionStatus":1,"ocppReady":"ocpp_1.6j","stateOfCharge":null,"maxChgCurrent":15,"maxAvailableCurrent":20,"maxChargingCurrent":12,"locked":0,"lastConnection":1648466234,"lastSync":{"date":"2022-03-27 16:33:53.000000","timezone_type":3,"timezone":"UTC"},"midEnabled":0,"midMargin":1,"midMarginUnit":1,"midSerialNumber":"","midStatus":0,"wifiSignal":50,"connectionType":"wifi","chargerLoadName":"Private","chargerLoadId":2,"chargingType":"AC","connectorType":"Type 2\/Socket","protocolCommunication":"wifi","accessType":"guest","powerSharingStatus":0,"resume":{"totalUsers":1,"totalSessions":21,"chargingTime":"239647","totalEnergy":"141749","totalMidEnergy":"0","energyUnit":"kWh"}},"users":[{"id":12345,"avatar":null,"name":"Ze","surname":"Kitez","email":"zzzz@gmail.com","profile":"super-admin","assigned":true,"createdByUser":false}]}}

Here’s an update where you set the max charging.
Call it from a flow with setMaxCharge=15
Do note… there is no check if you set it to low or to high… you might want to build that in

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

/**
 * set wallbox maxCharging function with token from Connect function
 */
async function setMaxCharging(token, max) {
  let maxCharging = { 'maxChargingCurrent': max };
  let mC = 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(maxCharging)
  }).then(response => response.json());
 
  if (mC.error === true) {
    return mC.message;
  }
  return true;
}

/**
 * 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
let actionArgs = args[0].split('=');

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

switch (actionArgs[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;
  case "setMaxCharge":
  
    if (typeof actionArgs[1] === 'undefined' ) {
      break;
    }
    token = await connectToWallbox();
    result = await setMaxCharging(token, actionArgs[1]);
    // Optional. You can leave the next 3 lines out and place them in a flow
    if (result === true) {
      say('Wallbox is ingesteld op maximaal laden van ' + actionArgs[1]);
    } else say( result );
    break;
}

When you unlock/lock the wallbox on a charge session base then the monthly cumulative kWh and other values is in the response message on the unlock/lock control. In ‘data.chargerdata’ the object ‘resume’, in JSON:

“resume”:{“totalUsers”:1,“totalSessions”:12,“chargingTime”:“185903”,“totalEnergy”:“86513”,“totalMidEnergy”:“0”,“energyUnit”:“kWh”}

  • “totalUsers”:1 // value, > 0 (?)
  • “totalSessions”:12 // value >= 0 , The total number of charging sessions
  • “chargingTime”:“185903” // string, can be ‘null’ or “0” or “a_value”, the total charging time in seconds
  • “totalEnergy”:“86513” // string, the total energy, but in milli kWh (mkWh)
  • “totalMidEnergy”:“0”, // ??
  • “energyUnit”:“kWh”

The fields are reset at the 1ste of each month (but when exactly…?) , example:
“resume”:{“totalUsers”:1,“totalSessions”:0,“chargingTime”:null,“totalEnergy”:0,“totalMidEnergy”:0,“energyUnit”:“kWh”}

I could verify the numbers from the logging of the month october with the Sessions in MyWallbox and they match. Its unclear what happens with the data of a charging session just before/during a month transition.

There is ‘current session’ data in the wallbox status but its not clear to me (yet) how the data behaves.

Thank you again @Sen-Sai :smile: Also big thanx to @Ze_Kitez
Works like a sharm. I will test a few apps and report back the ones that work. I will test some apps to control this automaticly and report back

There is more. From the screenshot: “Last session” is included in “November’s total” but “Today’s sessions” is not included (charged during the day transition of last night) and its unclear when it will be added to “November’s total”.
“Today’s sessions” is data from the state “added_energy”. When charging it’s updated every 30 seconds and seems to be the charge total of today. This includes a charge started yesterday but lasted until today. Thus I hope its included in the months total tomorrow.
The reponses from the wallbox also have lastSync or last_sync fields but… when, what, how, etc.
It takes time to figure it out.

Hi @Sen-Sai

Big thanks, now I can charge on times the energy-price is low.

One other question: I am using Power by the Hour, but it’s not always working the right way (some triggers aren’t correct). Will it be possible to get the EPEX prices of every hour and use them to do something in Homey (like PBTH does, but then the right triggers).

Or can I use PBTH (cause the prices are correct in that app) and build something to get some flows out of that data within that app (so not using the outcome of the app itself)?

And can I make a chart somewhere (Google Drive, or something) with the data for a divice within Homey? So for example a chart of usage of electricity and at the end of the day the price of that day I have to pay for the electricity used?

A lot of questions, but big thanks!!

Kind regards, Jibbe

Hi, the prices is configured in the app settings. Here is how i use that app to start charging at the cheapest hours. I use the Heating Controller app in Homey. It also has support for prices in the Nederlands.

Hi @Sen-Sai ,

How could I use this setmaxcharge as a Homey script? I don’t know which argument I have to use.
This one doesn’t work:

Schermafbeelding 2022-12-02 om 15.12.16

Kind regards!

Try not to use spaces around the = , see if that works

Doesn’t do the trick unfortunately (I used now this):

Schermafbeelding 2022-12-02 om 17.21.09

Do you use that script while charging or do you have to pause first?

Big thanks for your answer.

UPDATE:

Got it, you have to use setMaxCharge=
And not maxCharging=

Now it works!!

1 Like

How do I get the code for Homey to see if it is plugged in?
Cause I would like to put the wallbox on “locked” when plugged out.

Kind regards!

There is an option in the Wallbox app to lock automatically when plugged out.

Its a derived status added for a more easy interpretation of the status.
Example: “waiting for next schedule” or “waiting for car demand” is only reported when the wallbox can communicate with the car, so the cable is plugged in.
See ReadMe.md at https://github.com/zekitez/WandDeuze.

Found it, thanks!