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

Charging state of robot vacuum as source for power consumption sensor #639

Closed
RubenKelevra opened this issue Mar 27, 2022 · 38 comments
Closed
Assignees
Labels
enhancement New feature or request question Further information is requested

Comments

@RubenKelevra
Copy link
Contributor

Hey guys,

I was wondering if and how I can provide power consumption numbers for my robot vacuum to add it to the powercalc database for auto-detection?

@bramstroker
Copy link
Owner

Currently the database only consists of lights.
Initially when I designed the library loading code I also added support in model.json to provide fixed or linear configuration, so it should also be possible to add other devices to the database which don't have LUT files.
When we are going to allow addition of non lights to the DB I think we need to introduce a device type property to model.json. Then we can also make different sections in supported_models list to keep this organized.

Which vacuum cleaner do you have? And how does the power behave? Is it a constant power when the device is actively vacuum cleaning? And another fixed value when idle?

@bramstroker bramstroker added the question Further information is requested label Mar 27, 2022
@RubenKelevra
Copy link
Contributor Author

Hey @bramstroker,

well, not sure that there's really a need to distinguish different device types. I'm at least fine with just vendor/device name. :)

Which vacuum cleaner do you have?

The device is a Roborock S6 MaxV (Roborock is just a label for Xiaomi) — a pretty popular device.

And how does the power behave? Is it a constant power when the device is actively vacuum cleaning? And another fixed value when idle?

Well the base has an idle power consumption all the time (when the device is running) and a different idle consumption when the device is docked.

If the battery status is not 100% the device is charging, when it is reporting docked. I could provide a power consumption curve based on the state-of-charge as it is not static. :)

@bramstroker
Copy link
Owner

If the battery status is not 100% the device is charging, when it is reporting docked. I could provide a power consumption curve based on the state-of-charge as it is not static. :)

What do you mean by "power consumption curve based on the state-of-charge"?

First we need to figure out how to define powercalc configuration for the vacuum cleaner using the existing configuration options (linear, states_power, templates) etc.
When this is figured out we can think about adding it to the library of devices somehow.

@KrzysztofHajdamowicz
Copy link
Collaborator

What do you mean by "power consumption curve based on the state-of-charge"?

When battery is empty enough it's charging at max current provided by power supply. Above ~80% power supply moves from "constant current" to "constant voltage" and power draw decreases expotentially.
https://i.stack.imgur.com/ZNYHl.png

@bramstroker
Copy link
Owner

Is the state of charge (% battery) known to HA somehow when the device is in docked state.
I think a new strategy (besides linear, lut, fixed and wled) needs to be developed to facilitate this use case. Because we somehow need to define constant power for a few states (idle and cleaning), but a variable power for another state docked.
Or maybe a "composite" strategy which uses both fixed and linear (with the calibrate option) into a new strategy.
Anyway it gets rather complex.

@aetha
Copy link
Contributor

aetha commented Apr 20, 2022

Anyway it gets rather complex.

I’ve been giving this thought myself, and want to share those thoughts somewhere. I think an ideal implementation would be for a broad ‘charger’ class of devices. But complex is exactly right. Even more so, when there isn’t a consistent method to report the needed data across different integrations. Here’s a couple examples based on devices I own:

  • Vacuum: Valetudo via MQTT integration
    Detect activation with main entity vacuum.[name], state Docked
    Linear calculation (calibrated), from entity attribute battery_level
    Would need to check for battery full, trickle charging use, too.
  • UPS: via NUT integration
    Detect activation with level sensor sensor.[name]_battery_charge, state below 100
    Fixed calculation (according to spec, anyway)

For mobile devices: considering that different chargers have different efficiency characteristics & power delivery standards, or that you might charge these devices away from home — this use case isn’t worth implementing.

Implementing calibrated measurement also implies adding an additional mode to measure.py, to passively monitor power use during a full charge, (fully discharging the device first).

It’s a neat idea, but to implement it correctly would definitely take some work.

@RubenKelevra
Copy link
Contributor Author

Is the state of charge (% battery) known to HA somehow when the device is in docked state.

Yes of course:

The main state is docked and there's a battery_level attribute which is the SoC in percent.

So it's basically just a "lookup-table" for SoC and the average consumption for the SoC necessary.

This is how the consumption while charging looks like:

Screenshot from 2022-04-23 16-17-46

@KrzysztofHajdamowicz
Copy link
Collaborator

So it's basically just a "lookup-table" for SoC and the average consumption for the SoC necessary.

This is how the consumption while charging looks like:

Screenshot from 2022-04-23 16-17-46

So, basically user need to discharge vacuum and run a script to watch a battery level sensor and ask for power consumption and each battery percentage. This builds a lookup table and rest seems more straightforward.

@RubenKelevra
Copy link
Contributor Author

RubenKelevra commented Apr 23, 2022

Yep. But I guess it would be more accurate if we use the energy value on each SoC change instead. So it would automatically smooth out the power consumption for each SoC.

@RubenKelevra
Copy link
Contributor Author

RubenKelevra commented Apr 26, 2022

@bramstroker ah and something specific to vacuum cleaners: They won't get empty all the way, usually. Mine stops cleaning at 20% to make sure it gets back to the dock on its own, regardless how big the home is.

So I CAN discharge it more, by manually placing it somewhere and let it try to find the dock multiple times etc. but I don't think that's really necessary for a sensible energy profile. I think it's safe to assume that any battery charging rate in W below the minimum operation percentage is the same as the last in the profile.

So I would just need a way to specify the HASS string for the SoC and the Shelly plug to make this work :)

@bramstroker
Copy link
Owner

@RubenKelevra
I am not really sure how to read your chart. Could you elaborate more about at which state the vacuum cleaner was at particular points in the graph?
As I see all the lines are pretty much linear, so looks there is no need to implement any advanced system using LUT tables. Which will be a huge development effort anyways. As I need to adapt the measure script to work with other attributes than bri/hue/sat, need to rework the lut strategy, update readme's. Support this long term etc. etc.

Screenshot 2022-04-27 at 08 58 50

@RubenKelevra
Copy link
Contributor Author

Agreed it looks more stable than I thought. I think that was like a 40% to 100% charging. The 2 W on/off is trickle charging plus standby current to keep the device running.

@RubenKelevra
Copy link
Contributor Author

@bramstroker I'll take later a peek at the script. Maybe I just implement it myself - if you're fine with that.

Reason beeing that my device might be the exception in terms of linearity :)

@bramstroker
Copy link
Owner

bramstroker commented May 1, 2022

If I understand correctly the first stable 20 watt is ~40-80% charged, than the descending linear pattern from 15-8 watt is ~80-100% charged, and the last part trickle charge on 100%?

@bramstroker I'll take later a peek at the script. Maybe I just implement it myself - if you're fine with that.

Sure, PR's are welcome as well. measure script can first ask what kind of device you are measuring. i.e. light or vacuum. Than when in vacuum mode the script needs to listen for state changes of the battery_level somehow and write a row to CSV with the battery_level and power from the power meter, until 100% battery level is reached.

Reason beeing that my device might be the exception in terms of linearity :)

My philosofy is alway to keep things simple first KISS and actually implement something more complex when it is actually needed.

Regarding the implementation in the integration it can maybe look something like this.
With this approach we can just reuse the different available strategies, and only for the LUT strategy code needs to be altered to also read the battery_level, power format.

strategy_enabled_condition has to be added as well. When this is false powercalc needs to just return standby_power or 0. When it is true it uses the configured strategy (linear, fixed, lut) to calculate the power.

- platform: powercalc
  entity_id: vacuum.my_robot_cleaner
  strategy_enabled_condition: '{{ is_state('vacuum.my_robot_cleaner', 'docked') }}'
  linear:
    attribute: battery_level
    calibrate:
        - 1 -> 20
        - 79 -> 20
        - 80 -> 15
        - 99 -> 8
        - 100 -> 1.5

Or when using LUT mode:

- platform: powercalc
  entity_id: vacuum.my_robot_cleaner
  strategy_enabled_condition: '{{ is_state('vacuum.my_robot_cleaner', 'docked') }}'
  lut: #this can be omitted as it is the default

What do you think?

@RubenKelevra
Copy link
Contributor Author

Okay, I give a PR a shot. :)

My philosofy is alway to keep things simple first KISS and actually implement something more complex when it is actually needed.

Agreed. But I don't want to make it simple for me, but for the users. They shouldn't need to do any configurations, but instead have the device autodetected. :)

That's why I wanted to make a LUT for that.

@bramstroker
Copy link
Owner

The model.json files also provide possibilities for providing linear or fixed config, so it's not limited to LUT files per se for the model library and auto detection logic.

@KrzysztofHajdamowicz
Copy link
Collaborator

I agree, LUT with SoC-vs-wattage is most intuitive for use and flexible for future expansion.

@jacobdonenfeld
Copy link
Contributor

Great idea. I would love to measure state's of my sonos speaker, maybe different volumes, played vs paused, standby, and find some close map between that and watts

@wigster
Copy link

wigster commented Jun 12, 2022

When it is true it uses the configured strategy (linear, fixed, lut) to calculate the power.

- platform: powercalc
  entity_id: vacuum.my_robot_cleaner
  strategy_enabled_condition: '{{ is_state('vacuum.my_robot_cleaner', 'docked') }}'
  linear:
    attribute: battery_level
    calibrate:
        - 1 -> 20
        - 79 -> 20
        - 80 -> 15
        - 99 -> 8
        - 100 -> 1.5

What do you think?

I have a Roborock S7 (which is nearly the same vacuum as the OP) and it behaves in exactly the same way, modulo slightly different levels of fully charged power use. It would be great to be able to use this in exactly the way you suggest here, but it doesn't seem to be working in the released branch.

@bramstroker
Copy link
Owner

@wigster The strategy_enabled_condition option was only a proposal, never went ahead and implement this yet. Also the attribute option for linear mode is non existent yet.
I will implement this soon. This week or next week.

@bramstroker
Copy link
Owner

Good news, I just worked some time on this and the code has been merged into master. #789

Any of you guys able to test this:

- platform: powercalc
  entity_id: vacuum.my_robot_cleaner
  calculation_enabled_condition: "{{ is_state('vacuum.my_robot_cleaner', 'docked') }}"
  linear:
    attribute: battery_level
    calibrate:
        - 1 -> 20
        - 79 -> 20
        - 80 -> 15
        - 99 -> 8
        - 100 -> 1.5

This should work now. I am unable to test this fully as I don't have a robot cleaner myself. But did some testing using other attributes and entities.

@RubenKelevra
Copy link
Contributor Author

RubenKelevra commented Jun 19, 2022

@bramstroker can we share those "profiles" (or maybe better calibrations?) in the database? It would be neat to have them just as part of the auto detection, like bulbs and switches - if that's possible?

@bramstroker
Copy link
Owner

Sure, the model.json in library also supports fixed and linear mode.

So we should be able to do something like this:

{
    "name": "Roborock S6 MaxV",
    "supported_modes": [
        "linear"
    ],
    "measure_method": "manual",
    "measure_device": ".....",
    "measure_description": ".....",
    "linear_config": {
        "attribute": "battery_level"
        "calibrate": {
            "1": 20
            "79": 20
            "80": 15
            "99": 8
            "100": 1.5
         }
    }
}

calculation_enabled_condition is not supported yet in model.json, I will need to add that.

@bramstroker
Copy link
Owner

Has been implemented with #792
I don't have a vacuum cleaner myself, but I was able to test with a light using the following configuration.

{
    "measure_description": "Test",
    "measure_device": "Test",
    "measure_method": "script",
    "name": "Test",
    "supported_modes": [
        "linear"
    ],
    "calculation_enabled_condition": "{{ is_state('[[entity]]', 'on') }}",
    "linear_config": {
        "attribute": "brightness",
        "calibrate": [
            "1 -> 40",
            "79 -> 40",
            "80 -> 15",
            "99 -> 8",
            "100 -> 1.5"
        ]
    }
}

@wigster
Copy link

wigster commented Jun 24, 2022

Hi,

I think this works exactly as it should for my vacuum. However, once small tweak request: I would like to be able to have stand_by_power continue to be added when the calculation conditions is false. Right now it really seems to switch the energy use to zero. Basically this would allow the user to use the calculation condition as fake on/off switch.

@bramstroker
Copy link
Owner

bramstroker commented Jun 25, 2022

@wigster Just to verify, I will change it as follows:

assuming standby_power 0.25 and power 40

device_state calc_enabled power
OFF OFF 0.25
OFF ON 0.25
ON OFF 0
ON ON 40

@wigster
Copy link

wigster commented Jun 27, 2022

Hmm, not sure that's quite when I meant. For the case of the vacuum, I think, we have the following situation.

If calc_enabled is on = 40 W (to be precise, that linear scale). If calc_enabled is off (vacuum undocked), then it should be 0.25, because there is some residual power being taken by the docking station. The state of the vacuum device itself should not impact this at all, since if it turns itself off away from the dock, the dock doesn't know.

@bramstroker
Copy link
Owner

Should be resolved with #819

Now it will be:

device_state calc_enabled power
OFF OFF 0.25
OFF ON 0.25
ON OFF 0.25
ON ON 40

Can be tested by installing the master branch.

@bramstroker
Copy link
Owner

@wigster @RubenKelevra Are any of you able to test the suggested configuration? If it is working correctly it can be submitted as a profile to the library. So other users can also use it without any manual configuration.

@RubenKelevra
Copy link
Contributor Author

@bramstroker sure, I was under the impression that there's something left to implement and thus the solution is only academical. :)

@bramstroker
Copy link
Owner

@RubenKelevra Are you still able to add this configuration in a model.json to the library and test if this is working correct for your vacuum? Then we can close this issue.

@KrzysztofHajdamowicz
Copy link
Collaborator

image

I'm guessing mapping my vacuum is not a trivial task :D

@bramstroker
Copy link
Owner

I'm guessing mapping my vacuum is not a trivial task :D

Lol, how is it still using power for half an hour when fully charged :-P. Yeah this is highly complicated to build something for.

@bramstroker
Copy link
Owner

I was also thinking about having a look into smartphone charging using similar approach as implemented in this issue. The companion app passes charging state to HA afaik, so we should also maybe be able to use this somehow. Will do some testing on this.

@KrzysztofHajdamowicz
Copy link
Collaborator

I was also thinking about having a look into smartphone charging using similar approach as implemented in this issue. The companion app passes charging state to HA afaik, so we should also maybe be able to use this somehow. Will do some testing on this.

Phones have very flat charging curve, unless you are using some fast charging technique. In this case, my initial idea was to read notification bar, where AccuBattery displays charging stats.

@nepozs
Copy link
Contributor

nepozs commented Aug 10, 2022

@bramstroker @KrzysztofHajdamowicz
Charging a lithium-based battery always consists of 2 phases:

  1. constant current - CC (typical 0%-80%)
  2. constant voltage - CV (over 80%)

Sometimes CC phase ends at higher upper percent (and of course higher voltage) - service life of accu depends on that - higher % of change to CV -> lower accu service life.

High speed charging modifies only CC phase (in reality current is just not constant - it is based on temperature of battery).

It looks like BMS of this vacuum cleaner reports 100% battery when in reality it is just after end of CC phase.

Change CC -> CV is about at 85% real capacity of accu.
Looking at the chart above I've drawn some lines (from this sketch is is about 26/30 but my "Riemann intergration by hand" isn't accurate :P ).
183493832-5aa72357-f0f5-434e-b4e5-aee4faf07436_edit

@bramstroker bramstroker added the enhancement New feature or request label Aug 26, 2022
@bramstroker
Copy link
Owner

This issue got a little bit out of control ;-). Maybe we can start a discussion how to integrate phone charging support in a seperate discussion part.

Only thing left for this issue to be closed is getting some vacuum actually in the library.
@RubenKelevra Are you able to do that with you vacuum and the proposed configuration? And test if it's working correctly.
Let me know if you still need anything from my part.

Than we can close this issue.

@bramstroker bramstroker self-assigned this Aug 28, 2022
@bramstroker
Copy link
Owner

Closing because of inactivity.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request question Further information is requested
Projects
None yet
Development

No branches or pull requests

7 participants