Difference between revisions of "CO2MeterHacking"

From RevSpace
Jump to: navigation, search
(Investigation & findings: add link to another pdf describing info on a serial protocol)
 
(40 intermediate revisions by 3 users not shown)
Line 1: Line 1:
 
   {{Project
 
   {{Project
 
   |Name=CO2MeterHacking
 
   |Name=CO2MeterHacking
   |Status=Initializing
+
  |Picture=Voltcraft-c100.jpg
 +
   |Status=Completed
 
   |Contact= bertrik
 
   |Contact= bertrik
 
   }}
 
   }}
 +
 +
'''status: it works'''.
 +
We've modified the code to work using an ESP8266 which publishes the measurement data directly on an MQTT stream.
 +
 +
The G, C, D, V signals from the CO2-sensor inside the CO-100 are routed internally to the RJ45-plug, so there's actually no need to open it and solder a connector on the G, C, D, V lines. 
  
 
== Introduction ==
 
== Introduction ==
This project is about hacking the Voltcraft CO-100 CO2-sensor, such that we can read the exact ppm value as displayed on the LCD.
+
This project is about hacking the Voltcraft CO-100 CO<sub>2</sub>-meter, such that we can read the exact ppm value as displayed on the LCD.
 +
 
 +
This particular CO<sub>2</sub>-meter is present in the main space of RevSpace.
 +
Having the CO<sub>2</sub> ppm value available as a number allows for nice things such as logging the levels over time, announce them on IRC, show them on the [[LedBanner]], fine-grained control of the ventilation system, etc.
  
This particular CO2-sensor is present in the klusbunker at RevSpace and is currently used to control the ventilation in a crude manner (by monitoring the warning LEDs on the display module).
+
The user manual of the Voltcraft CO-100 says
Having the CO2 ppm value available as a number allows for nice things such as logging the levels over time, announce them on IRC, show them on the LedBanner , etc.
+
"Achtung! Der RJ45-Anschluss (siehe Kapitel 7, Position „K“) darf nicht verwendet werden. Der Anschluss ist nur für den Hersteller vorgesehen."
 +
Of course, a claim like that can only be interpreted as a challenge! :)
  
The user manual of the Voltcraft CO-100 says "Attention! The RJ45 connection (see chapter 7, item „K“) must not be used. The connection is only intended for the manufacturer". Of course, a claim like that can only be interpreted as a  challenge! :)
+
See also:
 +
* http://www2.zyaura.com/support/manual/pdf/ZyAura_CO2_Monitor_Carbon_Dioxide_ZG01C%20Module%20English%20user%20manual_1404.pdf
 +
* http://www.palebluedot.nl/jml/projects/arduino/52-reading-data-from-the-voltcraft-co-100
  
 
== Investigation & findings ==
 
== Investigation & findings ==
 
[[File:Co-100_overview.jpg|thumb|right|CO-100 internals]]
 
[[File:Co-100_overview.jpg|thumb|right|CO-100 internals]]
The CO2 sensor inside the CO-100 (in the left of the picture) has a sticker saying ZGw063RY.
+
The CO<sub>2</sub> sensor inside the CO-100 (in the left of the picture) has a sticker saying ZGw063RY.
Googling for this number reveals a CO2 module that looks just like the Voltcraft CO-100, so it appears that the CO-100 is basically just a rebranded [http://www.zyaura.com/products/ZGw063.asp ZyAura ZGw063RY] module.
+
Googling for this number reveals a CO<sub>2</sub> module that looks just like the Voltcraft CO-100, so it appears that the CO-100 is basically a rebranded [http://www.zyaura.com/products/ZGw063.asp ZyAura ZGw063RY] module.
  
 
The CO-100 seems to miss a bunch of components that can be mounted on the PCB, close to the RJ45 connection (most likely an RS232 chip with charge pump capacitors).
 
The CO-100 seems to miss a bunch of components that can be mounted on the PCB, close to the RJ45 connection (most likely an RS232 chip with charge pump capacitors).
 
[[File:Co-100.jpg|thumb|left|components around the RJ45 connector]]
 
[[File:Co-100.jpg|thumb|left|components around the RJ45 connector]]
  
The CO2 sensor in the CO-100 is a [http://www.zyaura.com/products/ZG_module.asp ZyAura ZG-01 module].
+
http://co2meters.com/Documentation/AppNotes/AN146-RAD-0401-serial-communication.pdf has some information on what looks like a clone/similar device, describing a serial cable for the RJ45, and the protocol used, as well as some info on re-calibration. Commands/Identifiers seem to match.
This sensor uses the ZyAura protocol, which vaguely resembles SPI, see [[File:ZyAura_CO2_Monitor_Carbon_Dioxide_ZG01_Module_english_manual-1.pdf|ZG01 CO2 Monitor Module user manual]].
+
 
 +
The CO<sub>2</sub> sensor in the CO-100 is a [http://www.zyaura.com/products/ZG_module.asp ZyAura ZG-01 module].
 +
This sensor uses the ZyAura protocol, which vaguely resembles SPI, see [[File:ZyAura_CO2_Monitor_Carbon_Dioxide_ZG01_Module_english_manual-1.pdf|ZG01 CO<sub>2</sub> Monitor Module user manual]].
  
 
On the bottom left of the PCB is a set of pads that are marked with G, C, D, V, meaning Ground, Clock, Data, Voltage of the ZG01 sensor.
 
On the bottom left of the PCB is a set of pads that are marked with G, C, D, V, meaning Ground, Clock, Data, Voltage of the ZG01 sensor.
The voltage level on these pins is 3.3V.
+
The voltage level on the clock and data pins is 3.3V (the voltage on V pin is 3.3V too).
  
 
The ZG-01 sends 5-byte frames containing measurement values:
 
The ZG-01 sends 5-byte frames containing measurement values:
* byte 0 is an identifier for the measurement item, e.g. whether it is a CO2 ppm value or a temperature.
+
* byte 0 is an identifier for the measurement item, e.g. whether it is a CO<sub>2</sub> ppm value or a temperature.
 
* byte 1 and 2 contain the value of the item (byte 1 is the MSB, byte 2 is the LSB)
 
* byte 1 and 2 contain the value of the item (byte 1 is the MSB, byte 2 is the LSB)
* byte 2 is a checksum over bytes 0-2, just the sum modulo 256.
+
* byte 3 is a checksum over bytes 0-2, just the sum modulo 256.
* byte 3 is always 0x0D
+
* byte 4 is always 0x0D
Besides the CO2 ppm value and temperature, it also sends various other (so far unknown) measurement items.
+
Besides the CO<sub>2</sub> ppm value and temperature, it also sends various other (so far unknown) measurement items.
  
 
Measurement items encountered so far:
 
Measurement items encountered so far:
Line 41: Line 55:
 
! Remark
 
! Remark
 
|-
 
|-
| 0x41 || 3290 || ?
+
| 0x41 'A' || 3290 || Relative humidity in units of 0.01%
 
|-
 
|-
| 0x42 || 4708 || Temperature in hexi-degrees Kelvin
+
| 0x42 'B' || 4708 || Temperature in Kelvin (unit of 1/16th K)
 
|-
 
|-
| 0x43 || 2964 || ?
+
| 0x43 'C' || 2964 || ?
 
|-
 
|-
| 0x46 || 6882 || ?
+
| 0x46 'F' || 6882 || Temperature in degrees Fahrenheit (unit of 0.01)?
 
|-
 
|-
| 0x4F || 7754 || ?
+
| 0x4F 'O' || 7754 || ?
 
|-
 
|-
| 0x50 || 857 || CO2 ppm value
+
| 0x50 'P' || 857 || CO<sub>2</sub> concentration in ppm
 
|-
 
|-
| 0x52 || 10438 || Pressure?
+
| 0x52 'R' || 10438 || Barometric pressure?
 
|-
 
|-
| 0x56 || 10443 || Pressure?
+
| 0x56 'V' || 10443 || Barometric pressure?
 
|-
 
|-
| 0x57 || 7880 || ?
+
| 0x57 'W' || 7880 || ?
 
|-
 
|-
| 0x6D || 2559 || ?
+
| 0x6D 'm' || 2559 || Seems to always have same value
 
|-
 
|-
| 0x6E || 17146 || ?
+
| 0x6E 'n' || 17146 || ?
 
|-
 
|-
| 0x71 || 855 || Always close to value of item 0x50
+
| 0x71 'q' || 855 || Always close to value of item 0x50
 
|}
 
|}
  
  
== Software ==
+
Pin-out of the 8P8C ("RJ45") connector on the side of the CO-100:
Software has been written to interface an arduino to the clock and data lines of the ZG-01.
+
{| class="wikitable"
It consists of an finite state machine (FSM) that processes the data line on each falling edge of the clock line.
+
! T568B
The FSM assumes that a new frame is starting when the time between bits is more than 3 milliseconds.
+
! Colour
Measurements of the CO2 ppm level are sent over the air using a 2.4 GHz NRF24L01+ module.
+
! Signal
 +
|-
 +
| 1 || orange-white || Supply voltage out, measured about 5.7V
 +
|-
 +
| 2 || orange || DATA, 3.3V level
 +
|-
 +
| 3 || green-white || CLOCK, 3.3V level
 +
|-
 +
| 4 || blue || GND
 +
|}
  
Arduino pin mapping:
+
== Hardware ==
* digital pin 2 (PD2): ZG01 clock signal
+
* digital pin 3 (PD3): ZG01 data signal
+
  
* TODO: pin mapping of the NRF24L01+ module.
+
=== NRF version ===
 +
The ZG-01 module and NRF24L01+ transceiver are connected to the Arduino as follows:
 +
{| class="wikitable"
 +
! Arduino
 +
! Module
 +
! Remark
 +
|-
 +
| D2 || ZG-C || ZG01 clock signal
 +
|-
 +
| D3 || ZG-D || ZG01 data signal
 +
|-
 +
| GND || NRF-1, ZG-G || NRF ground, ZG01 ground
 +
|-
 +
| 3V3 || NRF-2 || NRF power
 +
|-
 +
| D8 || NRF-3 || NRF CE
 +
|-
 +
| D9 || NRF-4 || NRF CSN
 +
|-
 +
| D13 || NRF-5 || NRF SCK
 +
|-
 +
| D11 || NRF-6 || NRF MOSI
 +
|-
 +
| D12 || NRF-7 || NRF MISO
 +
|-
 +
| - || 8 || NRF IRQ - not connected
 +
|}
 +
 
 +
=== ESP version ===
 +
In the ESP version of the CO2 meter, signals from the ZG-01 module are connected as follows:
 +
 
 +
{| class="wikitable"
 +
! Wemos D1-mini
 +
! ZG01
 +
! Remark
 +
|-
 +
| D1 || ZG-C || ZG01 clock signal, 3.3V
 +
|-
 +
| D2 || ZG-D || ZG01 data signal, 3.3V
 +
|-
 +
| GND || ZG-G || ZG01 ground
 +
|-
 +
| 5V || ? || Supply voltage from 8P8C, about 6V!
 +
|}
 +
 
 +
== Software ==
 +
The basic function of the software on the arduino is to monitor the C and D signals, until a CO<sub>2</sub> measurement is received from the ZG-01, then send it using the wireless transceiver.
  
 
The source code can be found [https://github.com/bertrik/co2sensor on github].
 
The source code can be found [https://github.com/bertrik/co2sensor on github].
 +
This archive contains two arduino projects:
 +
* one for an Arduino Pro Mini, using an NRF24L01+ for the wireless connection
 +
* one for an ESP8266, sending measurement values directly to MQTT over the WiFi.
 +
 +
=== ZG-01 decoding ===
 +
The ZG-01 protocol is decoded using a simple state machine.
 +
On each falling edge of the clock line, a sample of the data line is taken until a total of 40 bits is received.
 +
If the time between a bit and the previous bit is longer than 2 milliseconds, it is assumed that a new 5-byte frame has started.
 +
 +
The technical description for a very similar CO2 module: [http://www.zyaura.com/support/demo/ZG106_FW_001.ExtSpec.pdf ZG106 protocol].
 +
 +
=== Wireless protocol ===
 +
 +
==== NRF ====
 +
To control the NRF24L01+ wireless transceiver, we use the
 +
[https://github.com/gcopeland/RF24 gcopeland fork of the RF24 library].
 +
This library has several important fixes over the original RF24 library (and is used in the receiver as well).
 +
 +
The wireless message consist of 7 bytes:
 +
* 0x06 "CO_2" <MSB> <LSB> for the CO<sub>2</sub> concentration message (in ppm)
 +
* 0x06 "HUMI" <MSB> <LSB> for the relative humidity message (in units of 0.01%)
  
== Integration ==
+
==== ESP ====
The plan to integrate the CO2 sensor into the space infrastructure is as follows:
+
The ESP version of the software uses MQTT to publish the measurement values, on the following topics (retained):
* Attach an arduino to the G, C, D, V lines. The arduino takes power from the V-line and decodes the SPI-like signals from the ZG-01 on the C-line and D-line.
+
* revspace/sensors/co2 with the CO2 concentration in ppm, e.g. "400 PPM"
* Connect an NRF24L01+ module to the arduino SPI port and send the CO2/temperature frames over the air to a central NRF24L01+ receiver (e.g. the one which handles the SkipButton, Nomz Bell). The unique 4-character id for the CO2 sensor is "CO_2".
+
* revspace/sensors/humidity with the relative humidity in percent, e.g. "43.56 %"
* From there on, the CO2/temperature data can be further processed (to be logged, sent to the ledbanner, announced on IRC, etc.)
+
* revspace/sensors/temperature with the temperature in degrees Celcius, e.g. "23.9 °C"
  
This requires only minimal modifications to the CO-100 modules itself and makes uses of the existing wireless infrastructure.
+
For example, running
 +
  mosquitto_sub -h revspace.nl -t revspace/sensors/co2 -v
 +
produces output like
 +
  revspace/sensors/co2 530 PPM
 +
  revspace/sensors/co2 530 PPM
 +
  revspace/sensors/co2 532 PPM
 +
  revspace/sensors/co2 533 PPM
  
== Future work ==
+
=== Graphs and heat maps ===
Future investigation:
+
Interesting visualizations:
* consider powering the Arduino from the 3.3V line coming from the CO2 sensor
+
* [http://keetweej.vanheusden.com/revspace/co2.php CO2 level heatmap]
* fix the wireless RF24 based protocol, it seems to work sometimes, but not all the time
+
* [https://revgraph.bewaar.me/dashboard/db/all-co2?from=now-3h&to=now CO2 level graph]
* investigate further into the unknown measurement items sent by the ZG01
+

Latest revision as of 13:33, 19 February 2018

Project CO2MeterHacking
Voltcraft-c100.jpg
Status Completed
Contact bertrik
Last Update 2018-02-19

status: it works. We've modified the code to work using an ESP8266 which publishes the measurement data directly on an MQTT stream.

The G, C, D, V signals from the CO2-sensor inside the CO-100 are routed internally to the RJ45-plug, so there's actually no need to open it and solder a connector on the G, C, D, V lines.

Introduction

This project is about hacking the Voltcraft CO-100 CO2-meter, such that we can read the exact ppm value as displayed on the LCD.

This particular CO2-meter is present in the main space of RevSpace. Having the CO2 ppm value available as a number allows for nice things such as logging the levels over time, announce them on IRC, show them on the LedBanner, fine-grained control of the ventilation system, etc.

The user manual of the Voltcraft CO-100 says "Achtung! Der RJ45-Anschluss (siehe Kapitel 7, Position „K“) darf nicht verwendet werden. Der Anschluss ist nur für den Hersteller vorgesehen." Of course, a claim like that can only be interpreted as a challenge! :)

See also:

Investigation & findings

CO-100 internals

The CO2 sensor inside the CO-100 (in the left of the picture) has a sticker saying ZGw063RY. Googling for this number reveals a CO2 module that looks just like the Voltcraft CO-100, so it appears that the CO-100 is basically a rebranded ZyAura ZGw063RY module.

The CO-100 seems to miss a bunch of components that can be mounted on the PCB, close to the RJ45 connection (most likely an RS232 chip with charge pump capacitors).

components around the RJ45 connector

http://co2meters.com/Documentation/AppNotes/AN146-RAD-0401-serial-communication.pdf has some information on what looks like a clone/similar device, describing a serial cable for the RJ45, and the protocol used, as well as some info on re-calibration. Commands/Identifiers seem to match.

The CO2 sensor in the CO-100 is a ZyAura ZG-01 module. This sensor uses the ZyAura protocol, which vaguely resembles SPI, see File:ZyAura CO2 Monitor Carbon Dioxide ZG01 Module english manual-1.pdf.

On the bottom left of the PCB is a set of pads that are marked with G, C, D, V, meaning Ground, Clock, Data, Voltage of the ZG01 sensor. The voltage level on the clock and data pins is 3.3V (the voltage on V pin is 3.3V too).

The ZG-01 sends 5-byte frames containing measurement values:

  • byte 0 is an identifier for the measurement item, e.g. whether it is a CO2 ppm value or a temperature.
  • byte 1 and 2 contain the value of the item (byte 1 is the MSB, byte 2 is the LSB)
  • byte 3 is a checksum over bytes 0-2, just the sum modulo 256.
  • byte 4 is always 0x0D

Besides the CO2 ppm value and temperature, it also sends various other (so far unknown) measurement items.

Measurement items encountered so far:

Item Value Remark
0x41 'A' 3290 Relative humidity in units of 0.01%
0x42 'B' 4708 Temperature in Kelvin (unit of 1/16th K)
0x43 'C' 2964  ?
0x46 'F' 6882 Temperature in degrees Fahrenheit (unit of 0.01)?
0x4F 'O' 7754  ?
0x50 'P' 857 CO2 concentration in ppm
0x52 'R' 10438 Barometric pressure?
0x56 'V' 10443 Barometric pressure?
0x57 'W' 7880  ?
0x6D 'm' 2559 Seems to always have same value
0x6E 'n' 17146  ?
0x71 'q' 855 Always close to value of item 0x50


Pin-out of the 8P8C ("RJ45") connector on the side of the CO-100:

T568B Colour Signal
1 orange-white Supply voltage out, measured about 5.7V
2 orange DATA, 3.3V level
3 green-white CLOCK, 3.3V level
4 blue GND

Hardware

NRF version

The ZG-01 module and NRF24L01+ transceiver are connected to the Arduino as follows:

Arduino Module Remark
D2 ZG-C ZG01 clock signal
D3 ZG-D ZG01 data signal
GND NRF-1, ZG-G NRF ground, ZG01 ground
3V3 NRF-2 NRF power
D8 NRF-3 NRF CE
D9 NRF-4 NRF CSN
D13 NRF-5 NRF SCK
D11 NRF-6 NRF MOSI
D12 NRF-7 NRF MISO
- 8 NRF IRQ - not connected

ESP version

In the ESP version of the CO2 meter, signals from the ZG-01 module are connected as follows:

Wemos D1-mini ZG01 Remark
D1 ZG-C ZG01 clock signal, 3.3V
D2 ZG-D ZG01 data signal, 3.3V
GND ZG-G ZG01 ground
5V  ? Supply voltage from 8P8C, about 6V!

Software

The basic function of the software on the arduino is to monitor the C and D signals, until a CO2 measurement is received from the ZG-01, then send it using the wireless transceiver.

The source code can be found on github. This archive contains two arduino projects:

  • one for an Arduino Pro Mini, using an NRF24L01+ for the wireless connection
  • one for an ESP8266, sending measurement values directly to MQTT over the WiFi.

ZG-01 decoding

The ZG-01 protocol is decoded using a simple state machine. On each falling edge of the clock line, a sample of the data line is taken until a total of 40 bits is received. If the time between a bit and the previous bit is longer than 2 milliseconds, it is assumed that a new 5-byte frame has started.

The technical description for a very similar CO2 module: ZG106 protocol.

Wireless protocol

NRF

To control the NRF24L01+ wireless transceiver, we use the gcopeland fork of the RF24 library. This library has several important fixes over the original RF24 library (and is used in the receiver as well).

The wireless message consist of 7 bytes:

  • 0x06 "CO_2" <MSB> <LSB> for the CO2 concentration message (in ppm)
  • 0x06 "HUMI" <MSB> <LSB> for the relative humidity message (in units of 0.01%)

ESP

The ESP version of the software uses MQTT to publish the measurement values, on the following topics (retained):

  • revspace/sensors/co2 with the CO2 concentration in ppm, e.g. "400 PPM"
  • revspace/sensors/humidity with the relative humidity in percent, e.g. "43.56 %"
  • revspace/sensors/temperature with the temperature in degrees Celcius, e.g. "23.9 °C"

For example, running

 mosquitto_sub -h revspace.nl -t revspace/sensors/co2 -v

produces output like

 revspace/sensors/co2 530 PPM
 revspace/sensors/co2 530 PPM
 revspace/sensors/co2 532 PPM
 revspace/sensors/co2 533 PPM

Graphs and heat maps

Interesting visualizations: