Drift with HX711 and 50kg halfbridge loadcell

Hey HA Community, i have a massive Drift in my Bed scale over night and have no Idea whats causing this, can you help?

Load cells are sensitive to temperature (they get bigger and smaller even microscopically), and also are sensitive to the material properties of their mounted surfaces, so you must compensate with a temperature sensor.

Source: tried to build a propane scale, mostly failed because of this.

I’m not sure if this will be any use to you but as I’m not interested any weight readings but only how many people are in bed, I use this code.

sensor:
  - platform: hx711
    name: "HX711 Value"
    dout_pin: D0
    clk_pin: D1
    gain: 128
    update_interval: 1s
    
    
    filters:
      - calibrate_linear:
          - -994515 -> 0
          - -1004000 -> 1

      - sliding_window_moving_average:
          window_size: 11
          send_every: 5
   
 
      - lambda: |-
        
           if (x <= 15.9) {
            return 0.0;
            } else {
              return x;
           }
           
      - lambda: |-

           if ((x >= 16.0) && (x <= 46)) {
            return 1.0;
            } else {
              return x;
           }

      - lambda: |-

           if ((x >= 46.1) && (x <= 500)) {
            return 2.0;
            } else {
              return x;
           }

    unit_of_measurement: kg
    accuracy_decimals: 0
      

The output…

They are mounted on 3D printed holders.

The Temperature dropped at the beginning of the night but stabilized.

I have implemented such a function, but the problem is that the drift is so large that the sensor detects two people when only one is in bed, and in the morning, when no one is in bed anymore, it does not return to zero without being recalibrated.

globals:
  - id: initial_zero
    type: float
    restore_value: yes
    # NOTE: make sure to align this value to the one used in "calibrate_linear" below!
    initial_value: '1272107'
    
  - id: auto_tare_enabled
    type: bool
    restore_value: yes
    initial_value: 'true'

  - id: auto_tare_difference
    type: float
    restore_value: yes
    initial_value: '0'
    
  - id: manual_tare_flag
    type: bool
    restore_value: no
    initial_value: 'false'

binary_sensor:
  - platform: template
    name: "Bed Occupied"
    device_class: occupancy
    lambda: |-
      if (id(bed_hx711_value).state > 40) {
        return true;
      } else {
        return false;
      }      
  - platform: template
    name: "Bed Full"
    device_class: occupancy
    lambda: |-
      if (id(bed_hx711_value).state > 140) {
        return true;
      } else {
        return false;
      }  

switch:
  ## Switch to enable/disable the auto tare feature
  - platform: template
    id: bed_continuous_tare_enabled
    name: "Bed Continuous Tare Enabled"
    lambda: |-
      return id(auto_tare_enabled);
    turn_on_action:
      - lambda: |-
          id(auto_tare_enabled) = true;
    turn_off_action:
      - lambda: |-
          id(auto_tare_enabled) = false;
  
  ## Switch used to initiate a manual tare
  - platform: template
    id: bed_manual_tare_action_switch
    name: "Bed Manual Tare Action"
    lambda: |-
      return id(manual_tare_flag);
    turn_on_action:
      - lambda: |-
          id(auto_tare_difference) = id(initial_zero) - id(bed_hx711_value_raw).state;
      - switch.turn_off: bed_manual_tare_action_switch
    turn_off_action:
      - lambda: |-
          id(manual_tare_flag) = false;


sensor:

  - platform: wifi_signal
    name: "Under Bed WiFi Signal Sensor"
    update_interval: 60s


  # template sensors from global variables
  - platform: template
    id: bed_initial_zero
    name: "Bed Initial Zero"
    lambda: |-
      return id(initial_zero);
    update_interval: 1s
    
  - platform: template
    id: bed_auto_tare_difference
    name: "Bed Auto Tare Difference"
    lambda: |-
      return id(auto_tare_difference);
    update_interval: 1s
    
  # sensors imported from home assistant
  - platform: homeassistant
    id: homeassistant_initial_zero
    entity_id: input_number.bed_initial_zero
    on_value:
      then:
        - lambda: |-
            id(initial_zero) = x;



  - platform: hx711
    id: bed_hx711_value_raw
    name: "Bed Weight Value"
    internal: True
    dout_pin: GPIO2
    clk_pin: GPIO14
    update_interval: 1s
    unit_of_measurement: kg
    filters:
      - sliding_window_moving_average:
          window_size: 5
          send_every: 1
    on_value:
      then:
        - sensor.template.publish:
            id: bed_hx711_value
            state: !lambda 'return id(bed_hx711_value_raw).state;'
        - if:
            condition:
              and:
                - lambda: 'return id(auto_tare_enabled);'
                # current bed value is below approx. 10KG (raw value -275743) aka nobody is standing on the scale
                - lambda: 'return id(bed_hx711_value).state < 10.0;'
            then:
              - if:
                  condition:
                    # current raw scale value is below expected zero value
                    - lambda: 'return id(bed_hx711_value_raw).state < (id(initial_zero) - id(auto_tare_difference));'
                  then:
                    # INcrease Auto-Tare offset to slowly align real zero value with expected zero value
                    - lambda: |-
                        id(auto_tare_difference) += 10;
                  else:
                    # DEcrease Auto-Tare offset to slowly align real zero value with expected zero value
                    - lambda: |-
                        id(auto_tare_difference) -= 10;

  # Mapped value to KG
  - platform: template
    id: bed_hx711_value
    name: "bed HX711 Value"
    internal: False
    filters:
      # apply auto_tare difference
      - lambda: 'return x + id(auto_tare_difference);'
      # apply rough calibration
      - calibrate_linear:
          # retrieve these values by evaluating the raw values with loads of known mass.
          # note that a bigger difference between measurements usually results in higher resolution,
          # so measure 0 Kg and the highest known mass you have (like f.ex. your own weight, measured by a normal scale with good accuracy)
          - 1272107-> 0
          - 1514973-> 102
      # map values below 0.1 to 0 (to decrease value changes due to random fluctuation)
      - lambda: |-
          if (x <= 0.1) {
            return 0.0;
          } else {
            return x;
          }
          
    unit_of_measurement: kg
    accuracy_decimals: 2
    update_interval: 0.2s

Is it possible that I have overloaded the load cells? I weigh 102 kg, and I don’t know how much my bed weighs. How much can load cells be overloaded before they are permanently damaged?

Cells drift and have hysteresis. Mount them to metal instead of 3-D printed anything to reduce the drift caused by material properties of the mount. Compensate for other type of drift by using a thermometer compensation and a correlation. Some day I will release my experimental Jupyter workbook to do these calculations.

Then I will have to solve the whole thing differently in the long run, because I have no way of making the holders out of metal. I’m just wondering that it seems to work for so many.

Did you ever find a solution? I am trying to build something similar (water dispenser tracking) and have exactly the same drifting issues.

Hi

I had same problem, read this tread to see my strugle and solution