Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wallbox interaction #59

Closed
wants to merge 19 commits into from
Closed

Wallbox interaction #59

wants to merge 19 commits into from

Conversation

mdhom
Copy link
Contributor

@mdhom mdhom commented Mar 6, 2022

This PR will enable the library to interact with the wallbox as known from the wallbox page on the web portal.

  • [X ] Decide on the start/stop/toggle behavior

This PR is still in progress

@othorg
Copy link

othorg commented Mar 6, 2022

def set_wb_charge_toggle(self, enable, keepAlive=False):
            """Setting the Wallbox charge function via rscp protocol locally.

            Args:
                enable (bool): True/False
                keepAlive (Optional[bool]): True to keep connection alive

            Returns:
                0 if success
                -1 if error
            """
            
            #barry_off = bytearray([0,0,0,1,0,0])
            barry_on = bytearray([0,0,0,0,1,0])

          
            if enable:
                pprint(barry_on)
                res = self.sendRequest(
                    (
                        "WB_REQ_DATA",
                        "Container",
                        [
                            ("WB_INDEX", "UChar8", 0),
                            ("WB_REQ_SET_EXTERN", "Container",
                            [
                                ("WB_EXTERN_DATA", "ByteArray", barry_on), 
                                ("WB_EXTERN_DATA_LEN", "UChar8", 6),
                            ])
                        ],
                    ),
                    keepAlive=keepAlive,
                )
                pprint(res)
            else:
                res = self.sendRequest(
                    (
                        "WB_REQ_DATA",
                        "Container",
                        [
                            ("WB_INDEX", "UChar8", 0),
                            ("WB_REQ_SET_EXTERN", "Container",
                            [
                                ("WB_EXTERN_DATA", "ByteArray", barry_off), 
                                ("WB_EXTERN_DATA_LEN", "UChar8", 6),
                            ])
                        ],
                    ),
                    keepAlive=keepAlive,
                )

            # validate return code for EMS_RES_WEATHER_REGULATED_CHARGE_ENABLED is 0
            if res[2][0][2] == 0:
                print("Ok...")
                return 0
                
            else:
                print("NOk...")
                return -1

With this function i can start/stop the wallbox ;-)

@mdhom
Copy link
Contributor Author

mdhom commented Mar 6, 2022

With this function i can start/stop the wallbox ;-)

I still believe that this isn't an actual start / stop behavior. When I run your code trying to start charging, the only thing that happens is that the "chargingCanceled" flag toggles, but no current is flowing...
I think there still are some puzzle pieces missing in understanding what is happening under the hood...

@othorg
Copy link

othorg commented Mar 6, 2022

As i wrote before...
Sun Mode has to be off. For me it works actually. We should figure out what in which modus your wallbox is (Sunmode or Mixed mode)

What do you think...
One function called like "wallbox_controller" or something like that, and we should figure out what byte-Sequences are valid?

@mdhom
Copy link
Contributor Author

mdhom commented Mar 6, 2022

my wallbox is in mixed mode and still no charging. I just saw that my phases where changed from 3 to 1 calling your start method.
image
That is how it looks like currently in the web portal

@othorg
Copy link

othorg commented Mar 6, 2022

ok. Did you ever seen the Button "Ladevorgang starten"? Than we should compare the wallbox settings on S10 itself...
Bildschirmfoto 2022-03-06 um 17 35 31

@mdhom
Copy link
Contributor Author

mdhom commented Mar 6, 2022

Ok, I made some tests. First it seems that my car wasn't accepting current, I now started charging via the cars app, now the wallbox is actually charging.

But still, the barry_on = bytearray([0, 0, 0, 0, 1, 0]) payload seems to be a toggle command. With repeatedly sending this payload, I can toggle the chargingCanceled flag (and the Ladevorgang starten button (dis-)appears accordingly). The chargingActive flag goes True as soon as current is actually flowing. In combination with knowing the chargingCanceled you can actually implement a start/stop behaviour with the toggle, outside of this library...

Whenever I send your barry_off = bytearray([0,0,0,1,0,0]) payload, charging isn't changed but my phases are set from 3 to 1. Which actually would make sense, because you are setting a different index of the array and I`m pretty sure that is modifying the phases, and not the "charging" state.

@othorg
Copy link

othorg commented Mar 6, 2022

Oh my fault... you are right. I had used following code

def set_wb_charge_toggle(self, enable, keepAlive=False):
            """Setting the Wallbox charge function via rscp protocol locally.

            Args:
                enable (bool): True/False
                keepAlive (Optional[bool]): True to keep connection alive

            Returns:
                0 if success
                -1 if error
            """
            
            #barry_off = bytearray([0,0,0,0,1,0])
            barry = bytearray([0,0,0,0,1,0])

          
            if enable:
                pprint(barry)
                res = self.sendRequest(
                    (
                        "WB_REQ_DATA",
                        "Container",
                        [
                            ("WB_INDEX", "UChar8", 0),
                            ("WB_REQ_SET_EXTERN", "Container",
                            [
                                ("WB_EXTERN_DATA", "ByteArray", barry), 
                                ("WB_EXTERN_DATA_LEN", "UChar8", 6),
                            ])
                        ],
                    ),
                    keepAlive=keepAlive,
                )
                pprint(res)

And in my mind i was a step ahead... So i think one function maybe "wallbox_controller" with different sets of byteArrays should work... What do you think?

@mdhom
Copy link
Contributor Author

mdhom commented Mar 6, 2022

not sure what you mean with the controller method. I would not want to have a user of the library need to handle bytearrays just for toggle switches in the wallbox, I would always wrap that special setting into a separate method. Internally I could introduce such a controller method for reusing the same code of sending the request. Is that what you meant?

@othorg
Copy link

othorg commented Mar 6, 2022

not sure what you mean with the controller method. I would not want to have a user of the library need to handle bytearrays just for toggle switches in the wallbox, I would always wrap that special setting into a separate method. Internally I could introduce such a controller method for reusing the same code of sending the request. Is that what you meant?

Yes, exactly... :-)

@mdhom
Copy link
Contributor Author

mdhom commented Mar 6, 2022

@vchrisb in this PR another 4-5 methods will be added to the e3dc client. Is there any plan on e.g. splitting some functionalities into subclasses, so that maintenance of code will be easier in the future? The _e3dc.py has already over 2k lines, I could think of some subclassing could help? E.g. something like that:

e3dc =E3DC(...)
wallbox = e3dc.get_wallbox(0)
wallbox.get_data()
wallbox.set_sun_mode()

Is that something that is planned, should I implement the new wallbox-feature like that or would you prefer just adding the new code to the _e3dc.py?

@vchrisb
Copy link
Collaborator

vchrisb commented Mar 6, 2022

For now I would suggest implementing it like the other methods in _e3dc.py for consistency.
Creating subclasses is probably a larger refactoring effort to be addressed separately.

@mdhom mdhom marked this pull request as ready for review March 6, 2022 20:47
@mdhom
Copy link
Contributor Author

mdhom commented Mar 6, 2022

@othorg I think the PR is ready for reviewing. Can you please test it again with your system?

Copy link
Collaborator

@vchrisb vchrisb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a few changes for consistency...

e3dc/_e3dc.py Outdated Show resolved Hide resolved
e3dc/_e3dc.py Outdated Show resolved Hide resolved
e3dc/_e3dc.py Outdated Show resolved Hide resolved
e3dc/_e3dc.py Outdated Show resolved Hide resolved
e3dc/_e3dc.py Outdated Show resolved Hide resolved
e3dc/_e3dc.py Outdated Show resolved Hide resolved
e3dc/_e3dc.py Outdated Show resolved Hide resolved
@mdhom
Copy link
Contributor Author

mdhom commented Mar 7, 2022

Two suggestions only: Description in function toggle_wallbox_charging should (could) be: Toggles charging of the wallbox via rscp protocol locally if sunModeOn = False

Is that really the case? I think it toggles the chargingCanceled flag even if sunMode is on. It behaves kind of a switch that can actively prohibit charging if chargingCanceled is set to true, otherwise the wallbox decides on its own, when it charges and when not. What do you think?

In my opinion it would be great to have another function to set the max current like in the webinterface? What do you think? Then you have created a complete library for the wallbox....

Yes you're right, I forgot that and also setting the number of phases. I added both functionalities right now, please test once again.

@othorg
Copy link

othorg commented Mar 7, 2022

Yes you're right, I forgot that and also setting the number of phases. I added both functionalities right now, please test once again.

I remember that the new wallboxes (smart connect) can't set the phases. This setting in my opinion tells the wallbox only to detect the amount of phases for starting the charging process. I think this function is an older relict of the old wallbox. The old one could switch the phases inside the wallbox.

Attached ist the modbus documentation. Maybe it helps to understand my thoughts...
Bildschirmfoto 2022-03-07 um 08 54 52

@othorg
Copy link

othorg commented Mar 7, 2022

Is that really the case? I think it toggles the chargingCanceled flag even if sunMode is on. It behaves kind of a switch that can actively prohibit charging if chargingCanceled is set to true, otherwise the wallbox decides on its own, when it charges and when not. What do you think?

ok. Than we should explain it a bit more in this function.
But my first expectation is to toggle immediately the charging process. And this happens only if the sunMode is switched off. This is my perception at the moment. In the webportal it's not possible to charge (button is not visible) if the sun mode is on. If i toggle the sun mode to off (Webportal) than it's possible to start the charging process.
Maybe it depends on the settings in the S10 itself?
IMG_0982

@othorg
Copy link

othorg commented Mar 7, 2022

@mdhom regarding #59 set_wallbox_max_charge_current...
Do you think it's useful to build an exception, if the parameter value (int) is higher as the possible/permitted value in the S10 (I think 16A/32A)?

@mdhom
Copy link
Contributor Author

mdhom commented Mar 7, 2022

@mdhom regarding #59 set_wallbox_max_charge_current... Do you think it's useful to build an exception, if the parameter value (int) is higher as the possible/permitted value in the S10 (I think 16A/32A)?

have you tested what happens / is returned if you set an invalid current? Maybe we actually get an error in return...

Copy link
Contributor

@mstv mstv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you very much!
This has enabled me to implement my own "sun mode" adapted to my BEV, which does not charge or charges much less at lower allowed currents.

wallbox_power_by_current =
{
    # ...
    12:  6950,
    11:  6400,
    10:  5550,
     9:  4850,
     8:  2000
}

e3dc/_e3dc.py Outdated Show resolved Hide resolved
e3dc/_e3dc.py Outdated Show resolved Hide resolved
extern_data_net = rscpFindTag(req, "WB_EXTERN_DATA_NET")
if extern_data_net is not None:
extern_data = rscpFindTagIndex(extern_data_net, "WB_EXTERN_DATA")
outObj["consumptionNet"] = struct.unpack("h", extern_data[0:2])[0]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The total consumption from the grid in watthours is returned in extern_data[2:6].
The value seems to be reset by the WB only if no car is connected and nobody requests this value for a few minutes (or hours).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you mean instead of using extern_data[0:2], I should unpack extern_data[2:6]?

This comment was marked as resolved.

extern_data_sun = rscpFindTag(req, "WB_EXTERN_DATA_SUN")
if extern_data_sun is not None:
extern_data = rscpFindTagIndex(extern_data_sun, "WB_EXTERN_DATA")
outObj["consumptionSun"] = struct.unpack("h", extern_data[0:2])[0]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The total consumption from the solar panels in watthours is returned in extern_data[2:6].
The value seems to be reset by the WB only if no car is connected and nobody requests this value for a few minutes (or hours).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should I implement something here? or just a note?

This comment was marked as resolved.

e3dc/_e3dc.py Outdated
rsp_param_1 = rscpFindTag(req, "WB_RSP_PARAM_1")
if rsp_param_1 is not None:
extern_data = rscpFindTagIndex(rsp_param_1, "WB_EXTERN_DATA")
outObj["maxChargeCurrent"] = extern_data[2]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no need to send the dedicated request WB_REQ_PARAM_1.
The value is also returned in WB_EXTERN_DATA_ALG[3].

e3dc/_e3dc.py Outdated Show resolved Hide resolved
"energyAll": rscpFindTagIndex(req, "WB_ENERGY_ALL"),
"energySolar": rscpFindTagIndex(req, "WB_ENERGY_SOLAR"),
"soc": rscpFindTagIndex(req, "WB_SOC"),
"appSoftware": rscpFindTagIndex(req, "WB_APP_SOFTWARE"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is 0 for my E3DC Easy Connect WB.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here. Is that expected behaviour?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is 0 for my E3DC Easy Connect WB.

Same here. Is that expected behaviour?

I don't know. I guess this field is not supported / filled currently. Luckily, it is of little interest.

@mstv
Copy link
Contributor

mstv commented Apr 15, 2022

@mdhom regarding #59 set_wallbox_max_charge_current... Do you think it's useful to build an exception, if the parameter value (int) is higher as the possible/permitted value in the S10 (I think 16A/32A)?

have you tested what happens / is returned if you set an invalid current? Maybe we actually get an error in return...

My E3DC system clips the requested max_charge_current to the configured limits Min. Ladestrom and Absicherung (right of Max. Ladestrom / in the Wallbox Settings of the E3DC display).

@mdhom
Copy link
Contributor Author

mdhom commented May 1, 2022

@mdhom regarding #59 set_wallbox_max_charge_current... Do you think it's useful to build an exception, if the parameter value (int) is higher as the possible/permitted value in the S10 (I think 16A/32A)?

have you tested what happens / is returned if you set an invalid current? Maybe we actually get an error in return...

My E3DC system clips the requested max_charge_current to the configured limits Min. Ladestrom and Absicherung (right of Max. Ladestrom / in the Wallbox Settings of the E3DC display).

Thanks for testing, that is what I expected here. Once we have cleared your suggestions, I think this PR would be ready for completing.

@mdhom mdhom requested a review from vchrisb May 1, 2022 06:54
@mstv
Copy link
Contributor

mstv commented May 1, 2022

My wallbox has a key switch either for locking or for restriction to sun mode (depending on the wallbox configuration in the E3DC settings).
The keystate can be requested with ("WB_REQ_KEY_STATE", "None", None).


Whether the wallbox may discharge the battery can be controlled with ('EMS_REQ_SET_BATTERY_TO_CAR_MODE', "UChar8", 1 if enabled else 0)
and be read with ("EMS_REQ_BATTERY_TO_CAR_MODE", None, None).

@mdhom
Copy link
Contributor Author

mdhom commented May 2, 2022

awesome, where did you find those infos / how were you able to reverse-engineer those values?
I'll add the Keystate and discharge priority to this PR?

Edit: reading key state works (although I haven't physically toggled the keyswitch on my wallbox yet), but I fail to request the "Battery to car mode". Do you have some "example code" how to request that mode?

@mstv
Copy link
Contributor

mstv commented May 3, 2022

awesome, where did you find those infos / how were you able to reverse-engineer those values? I'll add the Keystate and discharge priority to this PR?

I have watched the data and compared it with the detailed charge info at the E-Mobility page.

The "energy*" values have automatically been reset multiple times in April, sometimes when my script lost the connection and perhaps at 100 kWh.
I.e. the documentation "consumed energy this month in watthours" might not be exact.

reading key state works (although I haven't physically toggled the keyswitch on my wallbox yet), but I fail to request the "Battery to car mode". Do you have some "example code" how to request that mode?

Sorry, it is ("EMS_REQ_BATTERY_TO_CAR_MODE", "None", None).

@bullitt186
Copy link
Contributor

Hi, As i see there are only very few changes do be done prior to merging this PR.
@mdhom Could you complete this PR? I'd like to use the WB features as well.
Thanks a lot!

@bullitt186
Copy link
Contributor

All,
I really would like to include the WB features implemented by @mdhom into python-e3dc.
I forked his branch and verified that it still works with 0.8.1 with a MultiConnect II ('get_wallbox_data()', 'toggle_wallbox_charging()', 'set_wallbox_max_charge_current()', 'set_wallbox_sunmode()'). I could not test 'set_wallbox_schuko()' as the Multiconnect II does not have a schuko outlet.

@vchrisb - what's open/pending in the PR?
I'd be happy to finish mdhom's work in a new PR from my fork, as it seems that @mdhom seems to have abandoned his fork?

@vchrisb
Copy link
Collaborator

vchrisb commented Oct 21, 2023

There is an open discussion between @mdhom and @mstv on a few topics I think.
I can't test this PR, as I don't have a wallbox.
A few wallbox users should test the PR and confirm it does work as expected.

@mstv
Copy link
Contributor

mstv commented Oct 21, 2023

If you want to see how I get the S10 & WB data using the unmodified release 0.7.3, you could look at https://github.com/mstv/e3dc_control/blob/main/control/e3dc_direct.py.

@bullitt186
Copy link
Contributor

Thank you @mstv, your code works fine for me, so I could integrate it in hacs-e3dc based on the current version of python-e3dc. However i think the "clean" way would be to get the features rightaway in this library.

I did yesterday some more testing throughout the day with this PR and my Wallbox and did not find any issues.
So I'd actually recommend to integrate the PR. By that we can integrate it in hacs-e3dc.
I guess by that we will also get more users using the WB features; if this reveals any bugs/issues, i am happy to follow up on these.

@mstv
Copy link
Contributor

mstv commented Oct 22, 2023

However i think the "clean" way would be to get the features rightaway in this library.

Of course. I just provided it in order to make my above comments clearer.

It would be good to

either in this or in a follow-up PR.

@T1ppes
Copy link

T1ppes commented Feb 16, 2024

It would be great if this change gets merged to gain access to Wallbox settings and information.
Unfortunately nothing happens for a while now.
Is there anyway I can help to get the issues resolved?

@mstv mstv mentioned this pull request Mar 31, 2024
@mstv
Copy link
Contributor

mstv commented Apr 6, 2024

@T1ppes, @bullitt186, @klepptor, @derhappy, @mdhom
Could you test #116, please?

@vchrisb
Copy link
Collaborator

vchrisb commented Apr 28, 2024

close in favor of #118

@vchrisb vchrisb closed this Apr 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants