Mosibi / Midea-heat-pump-ESPHome

Apache License 2.0
53 stars 14 forks source link

Switch with bitmask option #25

Closed matteo80 closed 1 month ago

matteo80 commented 10 months ago

Hi Mosibi great job, I have a question for the switch with the bitmask option. When I turn on the switch the bitmask goes on. When I turn off the switch the entire register goes to zero. I tested it both on the PC and on the heatpump. Do you have the same behavior?

Mosibi commented 9 months ago

Hi,

Can you tell with exact register and bit that is, then I will have a look at it.

matteo80 commented 9 months ago

I tried with Register 5, I turned on Silent Mode and it worked. When I turned it off, it also set the climate curve to 0. I then connected the esp to the computer via a usb-rs485 adapter and configured it in slave via modbus slave software. When I turn on individual switches, the individual bitmasks are activated, when I turn off a switch it sets the entire register to 0.

Mosibi commented 9 months ago

And then you are referring to this register (5) and bit (7) which you change?? In the current configuration this is still a binary_sensor, so not configurable yet.

  # Bit: 7
  - platform: modbus_controller
    modbus_controller_id: "${devicename}"
    name: "${entity_prefix} Function Setting Silent Mode Level"
    id: "${devicename}_function_setting_silent_mode_level"
    register_type: holding
    address: 0x5
    bitmask: 0x80

Did you change the code yourself to make it possible to set this specific register/bit?

matteo80 commented 9 months ago

Yes, I changed the settings to switch.

switch:
  - platform: modbus_controller
    modbus_controller_id: "${devicename}"
    name: "curve_on_off"
    id: curve_on_off
    register_type: holding
    address: 0x5
    bitmask: 0x1000

  - platform: modbus_controller
    modbus_controller_id: "${devicename}"
    name: "silent_level"
    id: silent_level
    register_type: holding
    address: 0x5
    bitmask: 0x40

  - platform: modbus_controller
    modbus_controller_id: "${devicename}"
    name: "echo"
    id: echo
    register_type: holding
    address: 0x5
    bitmask: 0x400

I analyzed better, when I activate one switch set all the others to 0. It's my mistake?

matteo80 commented 9 months ago

For the moment I use a Select sensor with lambda function to change only the bitmask, without changing the others, but it is complicated.

First I read the register and then I use the Select sensor with lambda to change the bitmask

sensor:
  # Registro 5 - Function setting
  - platform: modbus_controller
    modbus_controller_id: "${devicename}"
    name: "Function setting"
    id: function_setting
    register_type: holding
    address: 5
    value_type: U_WORD

select:
    # Registro 5 Bit 12 - Curve enable
  - platform: modbus_controller
    use_write_multiple: true
    modbus_controller_id: "${devicename}"
    name: "Curve enable"
    id: curve_enable
    address: 5
    value_type: U_WORD
    optionsmap:
      "Spenta": 0
      "Attiva": 4096
    lambda: |-
      //ESP_LOGE("main","Modbus Number incoming value = %d",x);
      //ESP_LOGE("main","Modbus eval value = %d",(x & 0x1000));
      if ((x & 0x1000) == 0)
        return  std::string("Spenta");
      if ((x & 0x1000) == 4096)
        return  std::string("Attiva");
      return {};
    write_lambda: |-
      //ESP_LOGE("main","Modbus write gets = %d",value);
      uint16_t unmodified =  id(function_setting).state;
      //ESP_LOGE("main","Modbus write unmodified = %d", unmodified);
      uint16_t modified = ((unmodified & ~0x1000) | value);
      //ESP_LOGE("main","Modbus write to write = %d", modified);
      return modified;
Mosibi commented 9 months ago

The lambda code makes it indeed a lot complexer. What you have to keep in mind is that you need to update the complete register in the lambda_write function.

If you look in the current heatpump.yaml in the master branch at register 270, https://github.com/Mosibi/Midea-heat-pump-ESPHome/blob/55c8d2bc704c80531018a7ab5d129a7eb80cdecb/heatpump.yaml#L2593, you see that I use "unmasked_value_register_270" which holds the original 16 bits value. That value is updated by the regular lambda (read) function on each run and in the write part, I update the specific bits and send that back to the heat pump.

When I develop such code, I often have the real write not enabled and use ESP_LOGI to show the incoming values and the outcome of the new value, until I am very sure that it delivers the right value.

matteo80 commented 9 months ago

Unfortunately I don't know the code that well. I found that solution in a shared config file on another forum for another heatpump. I just adapted it to my use, but it's still complicated. With the sensor switch I have the behavior that I described in the previous post. Does it work correctly for you? Thank you

Mosibi commented 9 months ago

In the end I will make everything configurable, it will be just a matter of time. I am now working on other registers, but I only work on it in the weekends.

So continue trying and learning, or just wait 😄

rysiulg commented 1 month ago

You must use globals for it -i personally extend this bits. if you use switch tan modbus controller don't klnow other bits settings -so it write whole uint16 register with only set bit you send 0like silent mode and disable others ;( Like in this project registers 270, 272, and t1s and curve is saved in globals and then used to get original value, changed to our specific change and saved to heatpump. Also there is missing tbt and tbt2 values -other description than main midea clone -York Monoblock So I modified processing for registers:

rysiulg commented 1 month ago

Yes, I changed the settings to switch.

switch:
 - platform: modbus_controller
   modbus_controller_id: "${devicename}"
   name: "curve_on_off"
   id: curve_on_off
   register_type: holding
   address: 0x5
   bitmask: 0x1000

 - platform: modbus_controller
   modbus_controller_id: "${devicename}"
   name: "silent_level"
   id: silent_level
   register_type: holding
   address: 0x5
   bitmask: 0x40

 - platform: modbus_controller
   modbus_controller_id: "${devicename}"
   name: "echo"
   id: echo
   register_type: holding
   address: 0x5
   bitmask: 0x400

I analyzed better, when I activate one switch set all the others to 0. It's my mistake?

No this doesn't work as expected ;(

rysiulg commented 1 month ago

In the end I will make everything configurable, it will be just a matter of time. I am now working on other registers, but I only work on it in the weekends.

So continue trying and learning, or just wait 😄

I've got all configurable ;) @Mosibi in my service manual for york (midea clone) heatpump registers 120 is for TBT1 temp and reg 121 for TBT2 -in your yaml there is Hydraulic Module Current 1 and 2 -is correct? I've also updated decode hp appliance -with my available data from SM


  # Register: 200 (High byte)
  - platform: modbus_controller
    modbus_controller_id: "${devicename}"
    name: "${entity_prefix} Home Appliance Type"
    id: "${id_entity_prefix}home_appliance_type"
    icon: "mdi:information-box-outline"
    register_type: holding
    address: 200
    response_size: 2
    raw_encode: HEXBYTES
    #value_type: U_WORD
    lambda: |-
         int idx = item->offset;
         std::string z = "";
         uint16_t rawdata = (uint16_t(data[idx]) << 8) + uint16_t(data[idx + 1]);
         ESP_LOGI("main", "The current version is 0x%x", rawdata);
         if ((rawdata >> 8) == 7) {
           z = "Air to water heat pump";
         } else {
           z = std::to_string(data[idx]);
         }
         return {z};
    #   - map:
    #     7 -> Air to water heat pump
  # Register: 200 (Low byte, first 4 bits)
  - platform: modbus_controller
    modbus_controller_id: "${devicename}"
    name: "${entity_prefix} Home Appliance Sub Type"
    id: "${id_entity_prefix}home_appliance_sub_type"
    icon: "mdi:information-box-outline"
    register_type: holding
    address: 200
    response_size: 2
    raw_encode: HEXBYTES    
   # bitmask: 0xF000
    lambda: |-
         int idx = item->offset;
         std::string z = "";
         uint16_t rawdata = (uint16_t(data[idx]) << 8) + uint16_t(data[idx + 1]);
         ESP_LOGI("main", "The current version is 0x%x", rawdata);
         if (((rawdata & 0x00F0) >> 4) == 2) {
           z = "R32";
         } else {
           z = std::to_string((rawdata & 0x00F0) >> 4);
         }
         return {z};
      # - map:
      #   2 -> R32
  # Register: 200 (Low byte, second 4 bits)
  - platform: modbus_controller
    modbus_controller_id: "${devicename}"
    name: "${entity_prefix} Home Appliance Product Code"
    id: "${id_entity_prefix}home_appliance_product_code"
    icon: "mdi:information-box-outline"
    register_type: holding
    response_size: 2
    raw_encode: HEXBYTES    
    address: 200
    #bitmask: 0x0F00
    lambda: |-
         int idx = item->offset;
         std::string z = "";
         uint16_t rawdata = (uint16_t(data[idx]) << 8) + uint16_t(data[idx + 1]);
         ESP_LOGI("main", "The current version is %s rawdata ", String(rawdata, HEX).c_str());
         if (((rawdata & 0x0F) ) == 4) {
           z = "4";
         } else {
           z = std::to_string(rawdata & 0x0F) ;
         }
         return {z};
      # - map:
      #   2 -> R32``` 

And a little more ;)
Mosibi commented 1 month ago

@Mosibi in my service manual for york (midea clone) heatpump registers 120 is for TBT1 temp and reg 121 for TBT2 -in your yaml there is Hydraulic Module Current 1 and 2 -is correct?

That is the annoying part of these registers, not every Midea (clone) has exact the same usage/description for a register. I assume that the registers depend on the software version used by the heatpump and that Midea uses a specific software version for each model/type. The Midea clones are probably based on a specific Midea type/model and thus get that software version.

At some point I think I have to create multiple versions of the heatpump.yaml, based on the software version or model/type name.

I've also updated decode hp appliance -with my available data from SM

I would be nice if you could create a pull request for this.

If scrolled through your code and noticed that you are doing things like setting the leaving water temperature, based on the outside temperature, so that you have more control than which is originally present. I do the same, but I keep that outside the yaml/controller and use Home Assistant for that. My goal is to keep the configuration as dumb as possible and only add "enriched" sensors like your sliding time window for the outside temperature.

If you have such sensors that add information that can be used for logic/automations (in Home Assistant) which are useful for others, I gladly accept a pull request for them!

You have been busy!! 😉

rysiulg commented 1 month ago

@Mosibi Ye you right. The code should be simple and universal for others so it isn't neede to include -especially sensors from outside of heatpump -i think only things useful for others and working as standalone from this device is good to apply ;) -

I put commit with added functionallity to be able to read/write registers 0, 5, 210, 211 -i think thats all R/W registers (0 and 5 is corrected to remember original value -in other case like in this issue other values are reseted), ive added calculated COP, and human readable uptime of sensor, I think that removed !secrets isn't good choice -it's easier to apply editing secrets than running with phone to do captive portal (personally i don't even know what it looks), and after do factory reset -it is needed to run again with phone to this controller... ;) I think functionality to reenable heat pump DHS and zones to automatically start after defined time would be also great -especially when you change some parameyters -heatpump automatically turn off and you have to manually turn on. I think with added it with configurable switch to enable/disable this funcyion and defined by user time -configurable from www or hjomeassistant ;) I also noticed that when heatpump monoblock (like mine) in winter with lower temps, and when other heat source work also and heat pump don't run for some time eg few days -then water in pipes can freeze -so i put own external pump to be energized for few minuttes if pump_i doesn't run for more than some time eg 1-2 hours -driven by separate pin on ESP connected to Relay or SSR and this connected to external pump to make some water flow inside pipes in heatpump ;)

rysiulg commented 1 month ago

So @Mosibi you can close this PR after last commit pull request -there was started with register 5. or you can wait to apply rest register 210 and 211 -then you get whole config enabled by www or homeassistant or other ;)

Mosibi commented 1 month ago

I will close this as soon as I merged your PR for register 5