Trouble reading out Senseair S8 UART with BZ25

Hi there!

For the last couple of days I’ve been struggling to read data from a Senseair S8 CO2 sensor. The sensor is mounted inside a Trotec BZ25, which already has a nice little display and housing. What I try to achieve is similar to the well known Ikea Vindriktning modification, meaning: Leave all the excisting hardware inside the device and only read sensor values using RX only on an ESP. Enabling to read values on the display as well as through HA. In my case I’m using a D1 mini ESP8266 and soldered some wires directly to the sensor’s TX and RX, which still are attached to the BZ25.

I keep getting ‘Invalid preamble form SenseAir!’ messages with different values. Sometimes ‘Reading from UART timed out at byte X!’ as well. To make it even stranger, when I use 5V provided from the Trotec to power the ESP, I get messages that ‘SenseAir checksum doesn’t match’.

When I attach the S8 sensor directly to the ESP, without the hardware from de Trotec BZ25 attached, the sensor works just fine and data shows up. I have to mention it only works when both TX/RX are attached. It doesn’t work when only the RX on ESP side is used (reading only). This means the sensor works as well as the ESP Sensor Component, but I do want to use the Trotec BZ25 for its display and case.

Does anyone have a solution for this problem or can point me into a good direction?

Part of the code used:

uart:
#  tx_pin: GPIO15
  rx_pin: GPIO13
  baud_rate: 9600

sensor:
  - platform: senseair
    co2:
      name: "SenseAir CO2 Value"
    update_interval: 5s

It’s not so strange, Esp8266 is power hungry.
So power Esp separately and remember common ground (Esp GND to Trotec GND). Rx should be enough for listening.
Also remember to set baudrate to 0 in logger.

1 Like

Thank you for your quick reply. Sadly your suggestions don’t help and I’ve already tried all of them before.Notable though: Giving them common ground also results in ‘SenseAir checksum doesn’t match’. I’ve tried different powersources already.

Post a good photo and/or some wiring scheme.
Something is not matching…
What’s the logic voltage of Trotec?

1 Like

I suspect it relates to having two devices connected to one sensors rx/tx.

You may have to wire it as more of a MITM set-up.

Reviewing the source code may help you understand where there may be conflicts in commands/responses.

https://esphome.io/api/senseair_8cpp_source

Adding uart debug might help you see what’s happening message wise.

1 Like


A picture was a bit faster to make. Orange coming from the sensor’s TX to D7(GPIO13) on the ESP and black is the GND of the sensor, connected to the GND of the ESP. Other wires are currently not connected, used them for testing around.
To my understanding the S8 sensor outputs at 3.3V. I’ve spent some time to figure out at which voltage the rest of the Trotec works, but I can’t find any datasheet of the onboard chip… I’m continuing my search on that.

That should be enough.
Like @Mahko_Mahko suggested, uart debug is must in your case.
Ps. I’m not breadboard lover, constant connections take out some odds…

1 Like

I’m going to dive into debugging and compare it to the source code. I can’t find much info on the mitm suggestion, so I’m letting that rest for now. Breadboards and cheap duponts are indeed not ideal, but I wanted to test the whole setup before soldering it all together. :slight_smile:

1 Like

I agree perfectly, but at least make direct dupont connections without breadboard and try to “feel” that connections are tight.

2 Likes

Connected them directly to the D1’s ports before, but had the same results. In the meantime I’m going to try to make sense out of the debug logs.

2 Likes

If you can figure out how to just recieve the raw uart messages as presumably requested by the other device you may even find you are better off just trying to selectively read just the co2 measurements without having a sensair component.

The source code and uart messages will tell you thier structure. Then you could parse them into a sensor like this.

Just an idea.

1 Like

Using the debugger with the Trotec attached I get the following logs (see quotes):

Every reading starts with xFE x04 and looking to the source code, this shouldn’t trigger the ‘invalid preamble’ message…Right? Without the Trotec attached, the readings start with xFE x04 as well. :person_shrugging: I do see some kind of ‘stacking’ of readings after every ‘invalid preamble’ error.

INFO ESPHome 2024.10.2
INFO Reading configuration /config/esphome/test.yaml...
INFO Starting log output from ---------- using esphome API
INFO Successfully connected to test @ -------- in 0.009s
INFO Successful handshake with test @ -------- in 2.433s
[22:47:39][I][app:100]: ESPHome version 2024.10.2 compiled on Nov  8 2024, 22:43:04
[22:47:39][C][wifi:600]: WiFi:
[22:47:39][C][wifi:428]:   Local MAC: -------
[22:47:39][C][wifi:433]:   SSID: '---------'[redacted]
[22:47:39][C][wifi:436]:   IP Address: --------
[22:47:39][C][wifi:439]:   BSSID: --------[redacted]
[22:47:39][C][wifi:441]:   Hostname: 'test'
[22:47:39][C][wifi:443]:   Signal strength: -70 dB ▂▄▆█
[22:47:39][C][wifi:447]:   Channel: 11
[22:47:39][C][wifi:448]:   Subnet: 255.255.255.0
[22:47:39][C][wifi:449]:   Gateway: --------
[22:47:39][C][wifi:450]:   DNS1: ---------
[22:47:39][C][wifi:451]:   DNS2: ---------
[22:47:39][C][logger:185]: Logger:
[22:47:39][C][logger:186]:   Level: DEBUG
[22:47:39][C][logger:188]:   Log Baud Rate: 0
[22:47:39][C][logger:189]:   Hardware UART: UART0
[22:47:39][C][uart.arduino_esp8266:118]: UART Bus:
[22:47:39][C][uart.arduino_esp8266:119]:   TX Pin: GPIO15
[22:47:39][C][uart.arduino_esp8266:120]:   RX Pin: GPIO13
[22:47:39][C][uart.arduino_esp8266:122]:   RX Buffer Size: 256
[22:47:39][C][uart.arduino_esp8266:124]:   Baud Rate: 9600 baud
[22:47:39][C][uart.arduino_esp8266:125]:   Data Bits: 8
[22:47:39][C][uart.arduino_esp8266:126]:   Parity: NONE
[22:47:39][C][uart.arduino_esp8266:127]:   Stop bits: 1
[22:47:39][C][uart.arduino_esp8266:129]:   Using hardware serial interface.
[22:47:39][C][senseair:144]: SenseAir:
[22:47:39][C][senseair:145]:   CO2 'SenseAir CO2 Value'
[22:47:39][C][senseair:145]:     Device Class: 'carbon_dioxide'
[22:47:39][C][senseair:145]:     State Class: 'measurement'
[22:47:39][C][senseair:145]:     Unit of Measurement: 'ppm'
[22:47:39][C][senseair:145]:     Accuracy Decimals: 0
[22:47:39][C][senseair:145]:     Icon: 'mdi:molecule-co2'
[22:47:39][C][captive_portal:089]: Captive Portal:
[22:47:39][C][mdns:116]: mDNS:
[22:47:39][C][mdns:117]:   Hostname: test
[22:47:39][C][esphome.ota:073]: Over-The-Air updates:
[22:47:39][C][esphome.ota:074]:   Address: test.local:8266
[22:47:39][C][esphome.ota:075]:   Version: 2
[22:47:39][C][esphome.ota:078]:   Password configured
[22:47:39][C][safe_mode:018]: Safe Mode:
[22:47:39][C][safe_mode:019]:   Boot considered successful after 60 seconds
[22:47:39][C][safe_mode:021]:   Invoke after 10 boot attempts
[22:47:39][C][safe_mode:022]:   Remain in safe mode for 300 seconds
[22:47:39][C][api:140]: API Server:
[22:47:39][C][api:141]:   Address: test.local:6053
[22:47:39][C][api:143]:   Using noise encryption: YES
[22:47:41][W][senseair:049]: SenseAir checksum doesn't match: 0x2F66!=0x8A70
[22:47:41][D][uart_debug:158]: <<< "\xFE\x04\x02\x04f/\xCE\xFE\x04\x02\x04f/"
[22:47:46][W][senseair:030]: Invalid preamble from SenseAir! cefe0402 04662fce fe040204 66
[22:47:46][D][uart_debug:158]: <<< "\xCE\xFE\x04\x02\x04f/\xCE\xFE\x04\x02\x04f/\xCE\xFE\x04\x02\x04W\xEE\x1A\xFE\x04\x02\x04W\xEE\x1A\xFE\x04\x02\x04W\xEE\x1A\xFE\x04\x02\x04W\xEE\x1A\xFE\x04\x02\x04J.\x13\xFE\x04\x02\x04J.\x13"
[22:47:51][W][senseair:049]: SenseAir checksum doesn't match: 0x2E4A!=0x8A70
[22:47:51][D][uart_debug:158]: <<< "\xFE\x04\x02\x04J.\x13\xFE\x04\x02\x04J."
[22:47:56][W][senseair:030]: Invalid preamble from SenseAir! 13fe0402 0444afd7 fe040204 44
[22:47:56][D][uart_debug:158]: <<< "\x13\xFE\x04\x02\x04D\xAF\xD7\xFE\x04\x02\x04D\xAF\xD7\xFE\x04\x02\x04D\xAF\xD7\xFE\x04\x02\x04D\xAF\xD7\xFE\x04\x02\x048\xAE6\xFE\x04\x02\x048\xAE6\xFE\x04\x02\x048\xAE6\xFE\x04\x02\x048\xAE6"

Screenshot of logs without Trotec attached:
Schermafbeelding 2024-11-08 220305

@Mahko_Mahko That makes sense, but my programming skills are not quite where they need to be for this I guess. But every man can learn of course… :sweat_smile:

1 Like

Try totally removing the sensor and showing what you get in the debug logs.

What you need would probably be similar to this example, which if you spend a little time figuring out what it does I’m sure you could read and maybe adjust.

Per the source code, you would probably check the length of the message:
static const uint8_t SENSEAIR_PPM_STATUS_RESPONSE_LENGTH = 13;
then check a few bytes
(response[0] != 0xFE || response[1] != 0x04

You’d probably skip the checksum check and then figure out where the C02 data is:
const int16_t ppm = int16_t((response[length + 1] << 8) | response[length + 2]);

And publish that to a sensor per the example. Might sound hard but it’s not too bad.

This is assuming my approach is a decent one - maybe there is a better way to get both devices reading the sensor ok using the native component. I don’t know.

1 Like

The opposite. it will be triggered when those two bytes aren’t present.

1 Like

Whoopsy, typo. I meant that it’s strange that I only get the error with the Trotec attached and not without, whilst in both situations the message starts with the same values.

Your approach indeed sounds good, thank you for explaining the logic. I was hoping for a ‘standard’ solution, but it’s not the end of the world if it takes some programming to get it working. I can also ‘just’ use the PWM output of the S8 sensor, but I had trouble reading it out too. But that’s probably a hardware issue, since my multimeter read out nice readings between 0-3.3V. Perhaps leaving the UART for what it is and reading the PWM might be the easy but less rewarding option. :joy:

In the meanwhile I tried debugging/logging without a sensor component, but there is no data showing up in the logs then. Searched around to get that to work, but it’s close to bed time, so my brain is not functioning too fast.

1 Like

I’ve also had noise / corruption clean up in the past when I’ve soldered things and even moved from cheap boads to a better ESP32, being particularly dilegent with GNDs. There are some crappy D1 mini’s floating around.

Worth trying if it’s not a hassle.

1 Like

I’ve got S2 mini’s somewhere… Is that considered better?

Still no luck with debugging without a sensor component though, am I forgetting something?

I don’t know.
My assumption was that the other device would be requesting readings and so your debug would just need to passively listen for messages.
But my understanding of operations may be incorrect.

Did you notice how often the device seemed to update when used without esphome? If you breath on it does it change quickly or take a while?

1 Like

Oh yeah, the sensor is being read out every 3 seconds I think. The display constantly shows new values, so there should be data coming out. Nothing else changed in the code, only removed the sensor. I’m making a start with new code based on your example and info right now.

1 Like

Hmm yeah but if you can’t see debug messages coming in then that is weird and you will have nothing to parse.

Do you have dummy_receiver: true ?

I would personally give that a go too.