rytilahti / python-miio

Python library & console tool for controlling Xiaomi smart appliances
https://python-miio.readthedocs.io
GNU General Public License v3.0
3.64k stars 550 forks source link

Incorrect water level of air humidifiers #1135

Closed OleksandrBerchenko closed 2 years ago

OleksandrBerchenko commented 3 years ago

The water level of air humidifiers is incorrect (assuming that the value in Mi Home is correct).

You have the following code (https://github.com/rytilahti/python-miio/blob/master/miio/airhumidifier_miot.py#L135):

return int(self.data["water_level"] / 1.25)

1.25 here should be changed to 1.2. But you are right, 125 still means the full (actually, overflowing) tank.

UPDATE: The model of my air humidifiers is zhimi.humidifier.ca1.

rytilahti commented 3 years ago

Ping @bieniu

bieniu commented 3 years ago

1.25 here should be changed to 1.2

Why? Do we have any specification for this?

OleksandrBerchenko commented 3 years ago

We have the Mi Home application. If you change 1.25 to 1.2, you will get the identical value.

bieniu commented 3 years ago

Not on my humidifier, I have 98-96% when depth is 120.

OleksandrBerchenko commented 3 years ago

Oh, really? What model do you have? I have two zhimi.humidifier.ca1 with the latest firmware. They worked that way from the very beginning.

bieniu commented 3 years ago

Really, my zhimi.humidifier.ca1 works that way.

OleksandrBerchenko commented 3 years ago

Right now, I have the following values: Humidifer 1: MI Home: 84%, python-miio: 81% Humidifer 2: MI Home: 75%, python-miio: 72%

bieniu commented 3 years ago

What are the depth values for these percentages?

OleksandrBerchenko commented 3 years ago

What is the easiest way to print raw depth values? I'm using this library through Home Assistant.

bieniu commented 3 years ago

Add this to the configuration.yaml file:

logger:
  default: warning
  logs:
    homeassistant.components.xiaomi_miio: debug

With this, the log will show full humidifier states, look for lines with text "Got new state".

OleksandrBerchenko commented 3 years ago

Thanks, that works.

humidifier 1: depth: 68, water level: 54, mi home: 56 humidifier 2: depth: 95, water level: 76, mi home: 79

bieniu commented 3 years ago

For your humidifiers 1.2 gives much better results. I'm curious why for mine 1.25 is better. I'll try to make some research in this case but I don't know when. There was an attempt to break into my apartment, so my world is turned upside down now.

OleksandrBerchenko commented 3 years ago

Oh, I'm really sorry to hear that. That sounds awful!

No rush: I have already workarounded this issue by a correction formula in HA.

OleksandrBerchenko commented 3 years ago

Just in case, one more observation:

When the tank is full, depth is 120 and Mi Home displays 100%. But if you continue to add water, suddenly depth jumps to 125, but Mi Home continues to display 100%. In HA I just translated 125 to 101% that means "overflow". And BTW, if you open the cover, depth becomes something like 127 (as far as I remember).

bieniu commented 2 years ago

I made research and probably you're right, the depth value of 120 means full tank and 125 means tank overfilled. I'll prepare a fix.

bieniu commented 2 years ago

I tried to find some info in decompiled Mi Home app but with no success. I'm not familiar with decompiling apk files. @syssi You have shown snippets of app code in another thread. Maybe you can help? I don't want to change anything unless I'm 100% sure.

syssi commented 2 years ago

@bieniu Could you tell me the model names (f.e. zhimi.humidifier.ca1) of the devices you want to know the behaviour of?

bieniu commented 2 years ago

@syssi zhimi.humidifier.ca1 (MIIO), depth value zhimi.humidifier.ca4 (MIOT), water_level value

syssi commented 2 years ago
# Mi Home react plugin of the CA1

[...]
    }, {
      key: "_isShortageWater",
      value: function _isShortageWater() {
        if (MainPage.isCModel()) {
          if (this.state.depth !== -1 && this.state.depth < 12) {
            return true;
          } else return false;
        } else {
          return false;
        }
      }
    }, {
      key: "_getPercentWaterDepth",
      value: function _getPercentWaterDepth(value) {
        if (value > 120) {
          if (value === 127) return "--";
          value = 120;
        } else if (value === -1) value = 0;

        var x = value / 120 * 100;
        return parseInt(x);
      }
    }, {
[...]

[...]
    }, {
      key: "_getCenterViewBodyText",
      value: function _getCenterViewBodyText() {
        if (MainPage.isCModel()) {
          return this.state.power ? "" + this.state.humidity : "" + this._getPercentWaterDepth(this.state.depth);
        } else {
          return "" + this.state.humidity;
        }
      }
    }, {
      key: "_getCenterViewBottomText",
      value: function _getCenterViewBottomText() {
        var string = "";

        if (MainPage.isCModel()) {
          if (this.state.power) {
            if (this.state.depth === 127) {
              string = (0, _LocalStrings.getLocalStrings)().ca1_cover_removed;
            } else {
              if (this._isShortageWater()) {
                string = (0, _LocalStrings.getLocalStrings)().ca1_low_water;
              } else {
                string = (0, _LocalStrings.getLocalStrings)().remainder_water + " " + this._getPercentWaterDepth(this.state.depth) + "%";
              }
            }
          } else {
            if (this._isShortageWater()) {
              string = (0, _LocalStrings.getLocalStrings)().ca1_low_water;
            } else {
              string = "";
            }
          }
        } else {
          if (this.state.child_lock) {
            string = (0, _LocalStrings.getLocalStrings)().child_locked;
          }
        }

        return string;
      }
[...]

[...]
    }, {
      key: "_isV1",
      value: function _isV1() {
        return _miot.Device.model === "zhimi.humidifier.v1";
      }
    }], [{
      key: "isCModel",
      value: function isCModel() {
        return _miot.Device.model === "zhimi.humidifier.ca1" || _miot.Device.model === "zhimi.humidifier.cb1" || _miot.Device.model === "zhimi.humidifier.cb2";
      }
    }, {
      key: "_isCb",
      value: function _isCb() {
        return _miot.Device.model === "zhimi.humidifier.cb1" || _miot.Device.model === "zhimi.humidifier.cb2";
      }
    }, {
      key: "_isCb1",
      value: function _isCb1() {
        return _miot.Device.model === "zhimi.humidifier.cb1";
      }
    }, {
      key: "_isCb2",
      value: function _isCb2() {
        return _miot.Device.model === "zhimi.humidifier.cb2";
      }
[...]
syssi commented 2 years ago
# Mi Home react plugin of the CA4

[...]
    }, {
      key: "_isShortageWater",
      value: function _isShortageWater() {
        return this.state.depth !== -1 && this.state.depth < 13;
      }
    }, {
      key: "_getPercentWaterDepth",
      value: function _getPercentWaterDepth(value) {
        if (value > 120) {
          if (value === 127) {
            return "--";
          }

          value = 120;
        } else if (value === -1) {
          value = 0;
        }

        var x = value / 120 * 100;
        return Math.floor(x);
      }
    }, {
[...]

[...]
    }, {
      key: "_getCenterViewBodyText",
      value: function _getCenterViewBodyText() {
        return this.state.power ? "" + this.state.humidity : "" + this._getPercentWaterDepth(this.state.depth);
      }
    }, {
      key: "_getCenterViewBottomText",
      value: function _getCenterViewBottomText() {
        var string = "";

        if (this.state.power) {
          if (this.state.depth === 127) {
            string = (0, _LocalStrings.getLocalStrings)().ca1_cover_removed;
          } else if (this._isShortageWater()) {
            string = (0, _LocalStrings.getLocalStrings)().ca1_low_water;
          } else {
            string = (0, _LocalStrings.getLocalStrings)().remainder_water + " " + this._getPercentWaterDepth(this.state.depth) + "%";
          }
        } else if (this._isShortageWater()) {
          string = (0, _LocalStrings.getLocalStrings)().ca1_low_water;
        } else {
          string = "";
        }

        return string;
      }
    }, {

[...]
syssi commented 2 years ago

Ping me if you have questions.

bieniu commented 2 years ago

@syssi Thank you!