Trouble reading out Senseair S8 UART with BZ25

I think I’m the dummy. Forgot the dummy. :smiley:

Some of the data:

[00:10:35][D][uart_debug:114]: <<< FE:04:02:05:04:AF:B7
[00:10:37][D][uart_debug:114]: <<< FE:04:02:04:E5:6E:6F
[00:10:54][D][uart_debug:114]: <<< FE:04:02:04:94:AE:4B
[00:11:20][D][uart_debug:114]: <<< FE:04:02:06:E2:2E:CD

etc...

1 Like

Hooray!

With your help and the reference to the previous topic with a similar question, I managed to get it working to your approach! I also used ChatGPT to explain some of the operators and figuring out which bytes did represent the PPM value (I did not see the pattern in the sensor’s datasheet before lol). I still need to check if I need the code to be more solid, but with the bare minimum it works already. E.g. logging the size of the message did not seem to work properly, but I guess it’s not reallly helpful either. I’m super thankful to you!

uart:
  tx_pin: GPIO15
  rx_pin: GPIO13
  baud_rate: 9600
  debug:
    direction: RX
    dummy_receiver: true
    after:
      delimiter: "\r\n"
    sequence:
      - lambda: |-
          UARTDebug::log_hex(direction, bytes, ',');
          if (direction == UART_DIRECTION_RX)
            {
              if (bytes[0] == 0xFE && bytes[1] == 0x04)
              {
                int ppm = (bytes[3] << 8) | bytes[4];
                id(PPM_sensor).publish_state(ppm);
              }
            }

sensor:
  - platform: template
    name: "PPM"
    id: PPM_sensor
    device_class: carbon_dioxide
    state_class: measurement
    unit_of_measurement: "ppm"

Screenshot 2024-11-09 205223

1 Like

Nice one.

I think adding a check for the message length may be a good idea.

It’s possible that other messages might come through (perhaps relating to the automatic calibration etc), and not processing those might be a good idea.

You’d just want to parse ones of length= 7.

So adding in this check:

                if (bytes.size() == 7)                               // Check number of bytes

1 Like

Fair point, I’m going to try and add this check.

The line for checking the size in your example did not seem to work though. It only returned %d in the logs. I was expecting it to return the actual size.

ESP_LOGD("custom", "Bytes size: %d", bytes.size());

Hmm right. Not sure what’s going on there from top of head and no longer easy for me to check.

I think the size check probably works ok even if there’s something wrong with the logging statement.

1 Like

Right now I’m not using the ESP_LOGD line, only checking if (bytes.size() == 7), and that works! When I make it another number, data comes in, but doesn’t get published to the sensor. Again, thank you so much for your help!

Relevant code for reference:

logger:
  baud_rate: 0

uart:
  tx_pin: GPIO15
  rx_pin: GPIO13
  baud_rate: 9600
  debug:
    direction: RX
    dummy_receiver: true
    after:
      delimiter: "\r\n"
    sequence:
      - lambda: |-
          UARTDebug::log_hex(direction, bytes, ',');
          if (direction == UART_DIRECTION_RX)
            {
              if (bytes.size() == 7) 
              {
                if (bytes[0] == 0xFE && bytes[1] == 0x04)
                {
                int ppm = (bytes[3] << 8) | bytes[4];
                id(PPM_sensor).publish_state(ppm);
                }
              }
            }

sensor:
  - platform: template
    name: "PPM"
    id: PPM_sensor
    device_class: carbon_dioxide
    state_class: measurement
    accuracy_decimals: 0
    unit_of_measurement: "ppm"
    update_interval: 3s
1 Like

As a small clean-up you shouldn’t need the tx pin there now…

1 Like

Hehe true. It kept flooding the logs with a warning though, hence why it is there. But indeed, it may leave now.

A bit off topic, is there a similar ‘workaround’ to listen only on a I²C line that you know of?

1 Like

Not that I’m aware of. I have a bit more experience with uart.

1 Like