esphome / issues

Issue Tracker for ESPHome
https://esphome.io/
285 stars 34 forks source link

QMC5883L: z-axis register required #5731

Closed jcsouthworth closed 3 weeks ago

jcsouthworth commented 3 weeks ago

The problem

After this merge: https://github.com/esphome/esphome/pull/6458

qmc5883l requires z-axis register to be queried, otherwise x- and y-axes remain constant with what appears to be the first value returned. If only x- or y-axis is queried, issue exists. If only z-axis is queried, works as expected. If ( x- and/or y- ) and z-axis is queried, all work as expected. z-axis must be queried.

Since all axes were queried automatically prior to the merge, the band-aid fix is to just query z-axis in addition to the x- or y-axis you are querying and it works, but this is not intuitive and not how the documentation nor referenced merge advertise the behavior.

The same behavior is happening on two nodemcu 8266 boards and one ESP32 dev each with their own qmc5883l.

Which version of ESPHome has the issue?

2024.4.1

What type of installation are you using?

Home Assistant Add-on

Which version of Home Assistant has the issue?

2024.4.3

What platform are you using?

ESP8266/ESP32

Board

nodemcu

Component causing the issue

i2c/qmc5883l

Example YAML snippet

sensor: 
  - platform: qmc5883l
    field_strength_x:
      name: "QMC5883L Field Strength X"

#    field_strength_z: # field_strength_x works if these lines are not commented out
#      name: "QMC5883L Field Strength Z"

Anything in the logs that might be useful for us?

only x-axis enumerated:
[22:02:24][D][qmc5883l:137]: Got x=-3.18µT y=nanµT z=nanµT heading=nan° temperature=nan°C status=4
[22:02:25][D][qmc5883l:137]: Got x=-3.18µT y=nanµT z=nanµT heading=nan° temperature=nan°C status=4
[22:02:26][D][qmc5883l:137]: Got x=-3.18µT y=nanµT z=nanµT heading=nan° temperature=nan°C status=4
[22:02:27][D][qmc5883l:137]: Got x=-3.18µT y=nanµT z=nanµT heading=nan° temperature=nan°C status=4
[22:02:28][D][qmc5883l:137]: Got x=-3.18µT y=nanµT z=nanµT heading=nan° temperature=nan°C status=4
[22:02:29][D][qmc5883l:137]: Got x=-3.18µT y=nanµT z=nanµT heading=nan° temperature=nan°C status=4
[22:02:30][D][qmc5883l:137]: Got x=-3.18µT y=nanµT z=nanµT heading=nan° temperature=nan°C status=4
[22:02:31][D][qmc5883l:137]: Got x=-3.18µT y=nanµT z=nanµT heading=nan° temperature=nan°C status=4

same code with x-axis and z-axis enumerated:
[22:05:34][D][qmc5883l:137]: Got x=-13.39µT y=nanµT z=12.58µT heading=nan° temperature=nan°C status=5
[22:05:35][D][qmc5883l:137]: Got x=-8.39µT y=nanµT z=19.51µT heading=nan° temperature=nan°C status=5
[22:05:36][D][qmc5883l:137]: Got x=-12.39µT y=nanµT z=13.55µT heading=nan° temperature=nan°C status=5
[22:05:37][D][qmc5883l:137]: Got x=-12.97µT y=nanµT z=13.41µT heading=nan° temperature=nan°C status=5
[22:05:38][D][qmc5883l:137]: Got x=-12.51µT y=nanµT z=14.89µT heading=nan° temperature=nan°C status=5
[22:05:39][D][qmc5883l:137]: Got x=-9.70µT y=nanµT z=18.70µT heading=nan° temperature=nan°C status=5

Additional information

No response

jrtallen commented 3 weeks ago

I'm also experiencing this issue, and I can confirm that it started at 2024.4.0, and continues in 2024.4.1. I went back to 2024.3.2 for now.

There was a recent commit that added a temperature sensor to the QMC5883L module that is the likely culprit: https://github.com/esphome/esphome/pull/6456/

bakerkj commented 3 weeks ago

I am also experiencing this issue. I worked around by also querying the y and z axis.

jcsouthworth commented 3 weeks ago

Calling @tronikos! Hoping they can provide some insight.

tronikos commented 3 weeks ago

I'm sorry for causing this. It's strange that other registers don't work unless you request Z. I'm reverting my changes in https://github.com/esphome/esphome/pull/6650

I'm curious what are you using the QMC5883L for? I'm using it to read my water meter see https://github.com/tronikos/esphome-magnetometer-water-gas-meter I have a spare QMC5883L so I'm interested to hear any other cool projects.

jcsouthworth commented 3 weeks ago

I like the idea of the commit! I looked through and couldn't identify a reason for the failure mode so I agree roll back is probably best for now.

I use it for the same purpose you describe - reading water meter (7ms refresh - fastest it will go. Functions below this, but the output is still at 7ms intervals) and gas meter (38ms refresh). It has been incredibly reliable and accurate.

I also have an application monitoring when a motor is operating - use a filter to output std.dev of the one of the axes. Alerts me and allows me to immediately de-energize in case of no rotation.

jrtallen commented 3 weeks ago

I'm curious what are you using the QMC5883L for? I'm using it to read my water meter see https://github.com/tronikos/esphome-magnetometer-water-gas-meter I have a spare QMC5883L so I'm interested to hear any other cool projects.

I am also using it to monitor my water and gas meters, and sending the results to Home Assistant. It's been working great, and is incredibly accurate. It would be nice to have the temperature available, too, if you feel like taking another stab at this!

bakerkj commented 3 weeks ago

I'm curious what are you using the QMC5883L for? I'm using it to read my water meter see https://github.com/tronikos/esphome-magnetometer-water-gas-meter I have a spare QMC5883L so I'm interested to hear any other cool projects.

I am also using it to monitor my gas meter.

tronikos commented 3 weeks ago

@jcsouthworth How did you achieve 7ms refresh? Using my code I get ~5ms on ESP32 but only after setting the loop interval to 0 see https://github.com/tronikos/esphome-magnetometer-water-gas-meter/blob/1d78792730be45240fb8de0e90087faad970ef34/esphome-magnetometer.yaml#L32

https://github.com/esphome/esphome/pull/6647 will make that unnecessary

It would be nice to have the temperature available, too, if you feel like taking another stab at this

I didn't revert the temperature changes.

Since you are all using it to monitor water and gas meters it would be good to start using https://github.com/tronikos/esphome-magnetometer-water-gas-meter and report any feedback there or even send PRs with improvements.

jcsouthworth commented 3 weeks ago

How did you achieve 7ms refresh? Using my code I get ~5ms on ESP32 but only after setting the loop interval to 0 see https://github.com/tronikos/esphome-magnetometer-water-gas-meter/blob/1d78792730be45240fb8de0e90087faad970ef34/esphome-magnetometer.yaml#L32

this is all on an 8266:

sensor: 
  - platform: qmc5883l
    address: 0x0D
    oversampling: 64x   ## chose lowest oversampling for speed.
    range: 200uT
    update_interval: 7ms
    field_strength_z:   ## added internal z to mitigate issues with #6458
      id: qmc5883lz
    field_strength_x:   ## 15x increase in stddev during flow - best SNR for my installation
      id: qmc5883lx
      filters:
        - sliding_window_moving_average:    ## oversampling isn't good enough - average 4 readings to reduce noise
            window_size: 4
            send_every: 4
      on_value:
        then:
          - lambda: |-  ## if field is > 14uT and it was previously low
              if (x > 14 && !id(water_high)) {
                  id(water_counter_int) += 1;   ## increment internal counter
                  id(water_high) = true;  ## indicate magnetic field is now high
                  if (id(water_counter_int) % id(increment_multiplier) == 0) {  ## i opted not to perform this work on every rotation, but instead to do it every x rotations. I currently have increment_multiplier set to 4
                    id(water_counter_total) += id(water_increment) * id(increment_multiplier);  ## increment water meter by calibrated water_increment times increment_multiplier
                    id(water_counter_timestamp) = millis();   ## record the timestamp for water flowrate calculation
                    id(water_flow).update();  ## run component to update flowrate
                    id(water_total).update();   ## run component to update the total water flow
                    for (int i = 0; i < 35; i++)  ## I have lead pipes between city main and my water meter I use this counter to shift elements of an array that represents the length of stagnation of the water in each segment
                      id(water_main_elements)[i] = id(water_main_elements)[i+1];
                    }
                    id(water_main_elements)[35] = 0;    ## last element in the array (newest water in the pipe) has an age of zero
                    id(water_age).update();   ## update component that indicates the water age at the tap
                    id(water_dist).update();  ## update component that indicates the distance from the tap to "fresh" water
                  }
                } else if (x < 2 && id(water_high)) {   ## if field is < 2uT and it was previously high
                  id(water_high) = false;   ## indicate magnetic field is now low
                } 

#ESP_LOGD("custom", "High X %f %i", id(qmc5883lx).state, millis());   ##useful for troubleshooting
#ESP_LOGD("custom", "Low X %f %i", id(qmc5883lx).state, millis());  ##useful for troubleshooting