bramstroker / homeassistant-powercalc

Custom component to calculate estimated power consumption of lights and other appliances
MIT License
1.02k stars 265 forks source link

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

Closed RubenKelevra closed 2 years ago

RubenKelevra commented 2 years ago

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 commented 2 years ago

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?

RubenKelevra commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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:

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

@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 commented 2 years ago

@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 commented 2 years ago

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 commented 2 years ago

@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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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

jacobdonenfeld commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

@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 commented 2 years ago

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 commented 2 years ago

@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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

@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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

@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 commented 2 years ago

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

bramstroker commented 2 years ago

@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 commented 2 years ago

image

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

bramstroker commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

@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 commented 2 years ago

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 commented 2 years ago

Closing because of inactivity.

RubenKelevra commented 1 month ago

Sorry, totally forgot about this one. Maybe we could implement this into the measurement script?

So we can run the robot as empty as it gets, plug the dock into the power measuring device and specify how the vacuum is called in HA and how it's battery percentage attribute is called (if that's difficult to auto-detect), start the script and put the robot on the dock.

Then it will measure the average consumption per charging percentage. So say it is starting at 0% the measurement script will fetch the power consumption every second until 1% is hit and average it out and store it as 0%.

The 100% thingy, but still charging is more challenging, but maybe we could measure for an hour until longer, and use this as "first hour on the dock" average and then switch to the standby measurement done after that?

This would capture this and all other weird things, like robots maybe taking shorter or longer to go into deep sleep etc.

bramstroker commented 1 month ago

switch to the standby measurement done after that

What do you mean with this?

bramstroker commented 1 month ago

Btw I have started with some basic architecture to incoorporate charging devices in the measure tool. See #2603

RubenKelevra commented 1 month ago

switch to the standby measurement done after that

What do you mean with this?

Ah, sorry for not being clearer.

The idea is to start an average for the first hour of being at 100 % and then maybe another average for 15 minutes or so to get the real standby consumption. As most vacuum cleaners will be taking their sweet time to go into deep sleep or continue charging very slowly the last couple of percent, but showing 100 % in the stats. But after an hour they should be deep sleeping and we can measure their 24/7 standby, if they have nothing to do.

If we want to be pedantic, we could also measure averages of say 5 minutes slots after it hits 100% until 3 are roughly the same. This would allow us to be more accurate if the vacuum cleaner is idle for a short while at 100% and then starts cleaning again, or something like that.

I guess most people let them run daily and so the more simple solution would be enough, however I tend to automate each room with different automations, so sometimes it runs 5-6 times a day, sometimes it runs just once, that depends highly on what the motion sensors and door sensors "see" over the course of the day.

RubenKelevra commented 3 weeks ago

@bramstroker please reopen this ticket, to track the progress.

Do you need help for the implementation? :)

bramstroker commented 3 weeks ago

@RubenKelevra you can just track the mentioned PR: #2603. Might probably need some help on this. Especially the testing part and ironing out bugs. Maybe I continue a bit on the PR today.