Supporting spot energy pricing

On a sidenote since you mentioned you have a Tesla PW2.

According to the binding docs it cannot be (dis)charged from external, can it?
Is that just a binding limitation or the Tesla’s ?

The owner just got back to me saying he activated write API for the bat, and there we go.
The curl command succeeded, and so do my item commands now.
I was able to force discharging (well actually it only discharged at 0 W, need to investigate further)
But it has put the bat into manual operating mode and back, that worked, shifting charge power from bat to grid.

EDIT:
This is what happens when I set the intended discharge power (channel batteryDischargeRate) then set the batteryDischargingToGrid channel’s switch to ON.
Battery Charge/Discharge goes to 0 and the home is fed from grid instead of from battery

2026-03-02 15:29:54.994 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Executing batteryDischargingToGrid command
2026-03-02 15:29:55.000 [DEBUG] [hab.binding.sonnen.internal.communication.SonnenJSONCommunication] - ChargingOperationMode = {"EM_OperatingMode":"1"}
2026-03-02 15:29:55.001 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel batteryDischargingToGrid with state ON
2026-03-02 15:29:56.350 [DEBUG] [hab.binding.sonnen.internal.communication.SonnenJSONCommunication] - BatteryData = {"Apparent_output":96,"BackupBuffer":"0","BatteryCharging":false,"BatteryDischarging":false,"Consumption_Avg":2302,"Consumption_W":2250,"Fac":50.0,"Flow
ConsumptionBattery":false,"FlowConsumptionGrid":false,"FlowConsumptionProduction":true,"FlowGridBattery":false,"FlowProductionBattery":false,"FlowProductionGrid":true,"GridFeedIn_W":848.0,"IsSystemInstalled":1,"OperatingMode":"1","Pac_total_W":-3,"Production_W":3101,"
RSOC":100,"RemainingCapacity_Wh":20814,"Sac1":96,"Sac2":null,"Sac3":null,"SystemStatus":"OnGrid","Timestamp":"2026-03-02 15:29:55","USOC":100,"Uac":237.0,"Ubat":213.0,"dischargeNotAllowed":false,"generator_autostart":false}
2026-03-02 15:29:56.350 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel batteryChargingState with state OFF
2026-03-02 15:29:56.350 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel batteryDischargingState with state OFF
2026-03-02 15:29:56.350 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel batteryCharging with state 3 W
2026-03-02 15:29:56.351 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel batteryDischarging with state 0 W
2026-03-02 15:29:56.351 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel batteryChargingFromGrid with state ON
2026-03-02 15:29:56.351 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel batteryDischargingToGrid with state ON
2026-03-02 15:29:56.351 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel batteryOperationMode with state Manual
2026-03-02 15:29:56.351 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel consumption with state 2250 W
2026-03-02 15:29:56.352 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel gridFeedIn with state 848 W
2026-03-02 15:29:56.352 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel gridConsumption with state 0 W
2026-03-02 15:29:56.352 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel solarProduction with state null
2026-03-02 15:29:56.352 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel batteryLevel with state 100 %
2026-03-02 15:29:56.353 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel flowConsumptionBatteryState with state null
2026-03-02 15:29:56.353 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel flowConsumptionGridState with state null
2026-03-02 15:29:56.353 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel flowConsumptionProductionState with state null
2026-03-02 15:29:56.353 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel flowGridBatteryState with state null
2026-03-02 15:29:56.353 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel flowProductionBatteryState with state null
2026-03-02 15:29:56.353 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel flowProductionGridState with state null
2026-03-02 15:29:56.353 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel energyImportedStateProduction with state null
2026-03-02 15:29:56.353 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel energyExportedStateProduction with state null
2026-03-02 15:29:56.353 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel energyImportedStateConsumption with state null
2026-03-02 15:29:56.354 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel energyExportedStateConsumption with state null
2026-03-02 15:30:00.362 [DEBUG] [hab.binding.sonnen.internal.communication.SonnenJSONCommunication] - BatteryData = {"Apparent_output":96,"BackupBuffer":"0","BatteryCharging":false,"BatteryDischarging":false,"Consumption_Avg":2285,"Consumption_W":2248,"Fac":49.994,"Fl
owConsumptionBattery":false,"FlowConsumptionGrid":false,"FlowConsumptionProduction":true,"FlowGridBattery":false,"FlowProductionBattery":false,"FlowProductionGrid":true,"GridFeedIn_W":849.0,"IsSystemInstalled":1,"OperatingMode":"1","Pac_total_W":-3,"Production_W":3100
,"RSOC":100,"RemainingCapacity_Wh":20813,"Sac1":96,"Sac2":null,"Sac3":null,"SystemStatus":"OnGrid","Timestamp":"2026-03-02 15:30:00","USOC":100,"Uac":237.0,"Ubat":213.0,"dischargeNotAllowed":false,"generator_autostart":false}
2026-03-02 15:30:00.362 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel batteryChargingState with state OFF
2026-03-02 15:30:00.362 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel batteryDischargingState with state OFF
2026-03-02 15:30:00.363 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel batteryCharging with state 3 W
2026-03-02 15:30:00.363 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel batteryDischarging with state 0 W
2026-03-02 15:30:00.363 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel batteryChargingFromGrid with state ON
2026-03-02 15:30:00.364 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel batteryDischargingToGrid with state ON
2026-03-02 15:30:00.364 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel batteryOperationMode with state Manual
2026-03-02 15:30:00.364 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel consumption with state 2248 W
2026-03-02 15:30:00.366 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel gridFeedIn with state 849 W
2026-03-02 15:30:00.366 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel gridConsumption with state 0 W
2026-03-02 15:30:00.367 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel solarProduction with state null
2026-03-02 15:30:00.367 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel batteryLevel with state 100 %
2026-03-02 15:30:00.369 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel flowConsumptionBatteryState with state null
2026-03-02 15:30:00.369 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel flowConsumptionGridState with state null
2026-03-02 15:30:00.369 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel flowConsumptionProductionState with state null
2026-03-02 15:30:00.369 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel flowGridBatteryState with state null
2026-03-02 15:30:00.369 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel flowProductionBatteryState with state null
2026-03-02 15:30:00.369 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel flowProductionGridState with state null
2026-03-02 15:30:00.369 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel energyImportedStateProduction with state null
2026-03-02 15:30:00.369 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel energyExportedStateProduction with state null
2026-03-02 15:30:00.370 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel energyImportedStateConsumption with state null
2026-03-02 15:30:00.370 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel energyExportedStateConsumption with state null

I noticed that when I set the ForceDischargeToGrid switch to ON, on next update, Force Charge From Grid also gets update to ON.
So you cannot get charge without discharge at the same time. I wonder if that can be correct.

Smells like something’s wrongly mapped.
@Paul_Smedley can you check the mapping in the binding if that’s correct?

Edit:
Charging+Discharging commands are accepted now, but both result in the charge/discharge power going to 0, and the home being fed from the grid instead of from the battery.

I have no idea what’s wrong with these commands.

I wonder if it’s units of measure? I’ll add some code to log the URL called. I suspect instead of say 1000W, it’s setting the charge/discharge to 1.

no i don’t think so, the bat doesn’t know anything about UoM it just takes the literal number. Plus you can do a dry test yourself if in doubt.

What we see is:
When I issue a charge or discharge cmd, switching to manual mode takes place and works. Power flow from/into battery adapts effectively to 0 and the home runs off the grid.

But the forced charge or discharge value is ignored. No matter how large, if positive or negative, and no matter if charge or discharge.
I believe either A) the binding doesn’t send the right cmd or B) the bat ignores it.
Can you add HTTP debug outputs on API send and response?
Do you know a curl cmd to test manually?

Updated build logs the URL that is called.

To use curl, should be something like should discharge at 5kw

  • curl -X PUT -d EM_OperatingMode=1 --header 'Auth-Token: TOKEN' http://SYSTEM-IP/api/v2/configurations
    curl -X POST --header 'Auth-Token: TOKEN' http://SYSTEM-IP/api/v2/setpoint/discharge/5000
    
    

Using the binding, you should get the response logged already:

String response2 = HttpUtil.executeUrl("POST", urlStr2, header, null, "application/json", 10000);
logger.debug("DischargingOperationMode = {}", response2);

With curl that’s working! Charging does, too.

With latest binding, it’s a little weird. It does work once. But if I then switch off discharging and then set a different batteryDischargeRate and start discharging again, it’s again discharging with the previous figure.
I cannot get it to accept a new power amount, neither by sending a different batteryDischargeRate nor with additional batteryDischargingToGrid to OFF+ON
Weird!
With subsequent curl commands, it works to change the amount.
So where’s the difference to the binding implementation?
Maybe some too restrictive check on the amount?

This I’m seeing. Could you add the amount of power commanded to (dis)charge with to the debug output?

2026-03-03 15:15:35.743 [DEBUG] [hab.binding.sonnen.internal.communication.SonnenJSONCommunication] - ChargingOperationMode = {"EM_OperatingMode":"1"}
2026-03-03 15:15:35.756 [DEBUG] [hab.binding.sonnen.internal.communication.SonnenJSONCommunication] - DischargingOperationMode = true

If you download the same url again, I added an info line with the URLs

Here we are, the problem is you send “-1”:

2026-03-03 20:33:07.323 [INFO ][hab.binding.sonnen.internal.communication.SonnenJSONCommunication] - startStopBatteryDischarging: urlStr2 = http://192.168.170.45/api/v2/setpoint/discharge/-1
2026-03-03 20:33:07.832 [DEBUG] [hab.binding.sonnen.internal.communication.SonnenJSONCommunication] - ChargingOperationMode = {"EM_OperatingMode":"1"}
2026-03-03 20:33:07.832 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel batteryDischargingToGrid with state ON

That may or may not have been a special case, but more testing reveals you keep sending the old value.
Here I sent 201 first, 333 next. But subsequent cmds repeat 201.

2026-03-03 20:38:52.242 [INFO ] [hab.binding.sonnen.internal.communication.SonnenJSONCommunication] - startStopBatteryDischarging: urlStr2 = http://192.168.170.45/api/v2/setpoint/discharge/201

Must be something in your code to cause that older values are used I believe?

The channel with the charge value is ‘weird’ in that it’s not linked to json from the sonnen API.

I set it to -1 by default, but as soon as you change the value, the integer value within the binding should update to reflect the new value - see:

I could also consider when you change the charge rate, calling the start/stop charging function directly, bypassing the switch - but that may not be the best way forwards. Let me have a think…

I notice two things in that linked code:

  • The binding accepts only QuantityType (e.g. 100 W), but not Decimal type (100). Maybe @mstormi sometimes sent the latter?
  • The binding assumes the given value is sent in Watts, which will fail with e.g. 2.3 kW. It should convert the given value to Watts.

It probably also shouldn’t send -1, but log out a warning in that case.

Thanks Danny, I’ll work on this tonight!

No, I’ve always sent 100W. Never without the unit (although that should work, too, when the linked item is a Number:Power, no?), never scaled (kW instead of W).
So thanks for offering this, but no that’s not the reason.

@Paul_Smedley can you add a debug output in that code piece as “else” to see if the “if” always applies?

Done - same URL.

I’m not seeing any new output?

2026-03-03 23:56:43.642 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Executing batteryChargingFromGrid command
2026-03-03 23:56:43.643 [INFO ] [hab.binding.sonnen.internal.communication.SonnenJSONCommunication] - startStopBatteryCharging: urlStr2 = http://192.168.170.45/api/v2/setpoint/charge/-1
2026-03-03 23:56:43.647 [DEBUG] [hab.binding.sonnen.internal.communication.SonnenJSONCommunication] - ChargingOperationMode = {"EM_OperatingMode":"1"}
2026-03-03 23:56:43.647 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel batteryChargingFromGrid with state ON
2026-03-03 23:56:43.892 [DEBUG] [hab.binding.sonnen.internal.communication.SonnenJSONCommunication] - BatteryData = {"Apparent_output":92,"BackupBuffer":"0","BatteryCharging":false,"BatteryDischarging":false,"Consumption_Avg":271,"Consumption_W":281,"Fac":50.028,"FlowConsumptionBattery":false,"FlowConsumptionGrid":true,"FlowConsumptionProduction":false,"FlowGridBattery":false,"FlowProductionBattery":false,"FlowProductionGrid":false,"GridFeedIn_W":-284.0,"IsSystemInstalled":1,"OperatingMode":"1","Pac_total_W":-3,"Production_W":0,"RSOC":76,"RemainingCapacity_Wh":15812,"Sac1":92,"Sac2":null,"Sac3":null,"SystemStatus":"OnGrid","Timestamp":"2026-03-03 23:56:43","USOC":74,"Uac":231.0,"Ubat":213.0,"dischargeNotAllowed":false,"generator_autostart":false}
2026-03-03 23:56:43.892 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel batteryChargingState with state OFF
2026-03-03 23:56:43.892 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel batteryDischargingState with state OFF
2026-03-03 23:56:43.893 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel batteryCharging with state 3 W

Really 100W, not 100 W (with space)? If so, I’m surprised this works, but apparently this is accepted. TIL.

The item type is only relevant for the types the command is coerced into (a UoM item will try to parse into QuantityType, a plain Number item probably won’t). If I’m reading the parsing code correctly, the default unit seemingly is one.

Yes. But with a space it’s the same.

try again… I added a logging line even for the case where charge/discharge rate is set:

    if (channelUID.getId().equals(CHANNEL_BATTERY_CHARGE_RATE)) {
        if (command instanceof QuantityType quantityCommand) {
            chargeRate = quantityCommand.intValue();
            logger.info("chargeRate set to {}", chargeRate);
        } else {
            logger.info("chargeRate not set, {}", command);
        }
    }
    if (channelUID.getId().equals(CHANNEL_BATTERY_DISCHARGE_RATE)) {
        if (command instanceof QuantityType quantityCommand) {
            dischargeRate = quantityCommand.intValue();
            logger.info("dischargeRate set to {}", dischargeRate);
        } else {
            logger.info("dischargeRate not set, {}", command);
        }
    }

err, chargeRate set when discharging?

Same inversion when I charge I get dischargeRate output

Maybe confused the value for CHANNEL_BATTERY_DISCHARGE_RATE with CHANNEL_BATTERY_CHARGE_RATE ?

2026-03-04 00:19:48.137 [INFO ] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - chargeRate set to 555
2026-03-04 00:19:48.139 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Executing batteryDischargingToGrid command
2026-03-04 00:19:48.140 [INFO ] [hab.binding.sonnen.internal.communication.SonnenJSONCommunication] - startStopBatteryDischarging: urlStr2 = http://192.168.170.45/api/v2/setpoint/discharge/-1
2026-03-04 00:19:48.144 [DEBUG] [hab.binding.sonnen.internal.communication.SonnenJSONCommunication] - ChargingOperationMode = {"EM_OperatingMode":"1"}
2026-03-04 00:19:48.146 [DEBUG] [org.openhab.binding.sonnen.internal.SonnenHandler                ] - Update channel batteryDischargingToGrid with state ON