co2minimon

Get temperature and CO2 concentration data from a CO2Mini sensor.
git clone git://git.amin.space/co2minimon.git
Log | Files | Refs | README | LICENSE

commit f215c8bfb3234cf083fb492cf27b8cbf8fd8fe4e
Author: amin <dev@aminmesbah.com>
Date:   Tue, 28 Dec 2021 02:54:53 +0000

Get data from the co2mini through the hidraw api

But we fail to decode it. It looks [1] like they may have changed the
encryption system in the version of the hardware I have. I may need to
follow Henryk's steps and reverse engineer the new version.

[1]: https://hackaday.io/project/5301-reverse-engineering-a-low-cost-usb-co-monitor/discussion-168652

FossilOrigin-Name: ab94b787d128884e2f7c73cc082f6350256cb644d5dcede2e1e201af80f0e781
Diffstat:
A.gitignore | 1+
A99-co2mini.rules | 5+++++
AREADME.md | 5+++++
Amain.c | 101+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 112 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1 @@ +a.out diff --git a/99-co2mini.rules b/99-co2mini.rules @@ -0,0 +1,5 @@ +ACTION=="remove", GOTO="co2mini_end" + +SUBSYSTEMS=="usb", KERNEL=="hidraw*", ATTRS{idVendor}=="04d9", ATTRS{idProduct}=="a052", GROUP="wheel", MODE="0660", SYMLINK+="co2mini%n", GOTO="co2mini_end" + +LABEL="co2mini_end" diff --git a/README.md b/README.md @@ -0,0 +1,5 @@ +Put the udev rules in /etc/udev/rules.d/, then reload the rules with: + +``` +# udevadm control --reload-rules && udevadm trigger +``` diff --git a/main.c b/main.c @@ -0,0 +1,101 @@ +#include <assert.h> +#include <errno.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdint.h> + +#include <fcntl.h> // open() +#include <sys/ioctl.h> // ioctl() +#include <unistd.h> // close() + +#include <linux/hidraw.h> + +typedef uint8_t buffer[8]; + +// Made possible by Henryk Plötz' excellent work: +// https://hackaday.io/project/5301-reverse-engineering-a-low-cost-usb-co-monitor + +// references +// https://www.kernel.org/doc/Documentation/hid/hidraw.txt +int main(void) { + // NOTE: Included udev rules create this symlink to the appropriate hidraw + // entry. + int device_handle = open("/dev/co2mini0", O_RDWR); + if (device_handle < 0) { + printf("ERROR: Failed to open hid\n"); + return 1; + } + + buffer key = {0}; + int result = ioctl(device_handle, HIDIOCSFEATURE(sizeof(key)), key); + if (result < 0 || result != sizeof(buffer)) { + printf("ERROR: Failed to send feature report\n"); + return 1; + } + + while (true) { + buffer data = {0}; + int bytes_read = read(device_handle, &data, sizeof(buffer)); + if (bytes_read < 0 && (errno == EAGAIN || errno == EINPROGRESS)) { + bytes_read = 0; + } else { + assert(bytes_read == sizeof(buffer)); + } + + if (bytes_read == sizeof(buffer)) { + buffer decoded = {0}; + { + { + uint8_t tmp; + tmp = data[0]; data[0] = data[2]; data[2] = tmp; + tmp = data[1]; data[1] = data[4]; data[4] = tmp; + tmp = data[3]; data[3] = data[7]; data[7] = tmp; + tmp = data[5]; data[5] = data[6]; data[6] = tmp; + } + + for (int i = 0; i < sizeof(buffer); ++i) { + data[i] ^= key[i]; + } + + { + uint8_t tmp = (data[7] << 5); + decoded[7] = (data[6] << 5) | (data[7] >> 3); + decoded[6] = (data[5] << 5) | (data[6] >> 3); + decoded[5] = (data[4] << 5) | (data[5] >> 3); + decoded[4] = (data[3] << 5) | (data[4] >> 3); + decoded[3] = (data[2] << 5) | (data[3] >> 3); + decoded[2] = (data[1] << 5) | (data[2] >> 3); + decoded[1] = (data[0] << 5) | (data[1] >> 3); + decoded[0] = tmp | (data[0] >> 3); + } + + buffer dumb_proprietary_bullshit_secret_word = "Htemp99e"; + for (int i = 0; i < sizeof(buffer); ++i) + { + decoded[i] -= (dumb_proprietary_bullshit_secret_word[i] << 4) | (dumb_proprietary_bullshit_secret_word[i] >> 4); + } + } + + if (decoded[4] != 0x0d) { + printf("BAD DATA: "); + } else { + switch(decoded[0]) { + case 0x42: + printf("Temperature: "); + break; case 0x50: + printf("CO2: "); + break; + } + } + + for (int i = 0; i < sizeof(buffer); i++) { + printf("[%i]: %X ", i, decoded[i]); + } + + printf("\n"); + } + } + + close(device_handle); + return 0; +}