# ExCO₂Mini
ExCO₂Mini is a library to read carbon dioxide and temperature data from the CO₂Mini USB sensor, also known as the RAD-0301.
This library only reads data from the device. If you want to record that data somewhere, see e.g. [ddco2](https://github.com/wisq/ddco2) for recording to StatsD.
[![Build Status](https://travis-ci.org/wisq/ex_co2_mini.svg?branch=master)](https://travis-ci.org/wisq/ex_co2_mini)
[![Hex.pm Version](http://img.shields.io/hexpm/v/ex_co2_mini.svg?style=flat)](https://hex.pm/packages/ex_co2_mini)
## Device setup
**ExCO₂Mini currently only supports Linux.** Your device needs to show up as a `/dev/hidraw*` device, and it needs to be able to compile a small C utility that uses Linux-specific HID ioctls.
To allow a regular user to access the device, you can set up a `udev` rule, such as the following:
```udev
KERNEL=="hidraw*", ATTRS{idVendor}=="04d9", ATTRS{idProduct}=="a052", GROUP="co2meter", MODE="0640", SYMLINK+="co2mini"
```
(Don't forget to `udevadm control --reload-rules`.)
When the device is plugged in, this will set the device's group to `co2meter`, set group read (`g+r`) permissions on it, and create a `/dev/co2mini` symlink to it. (Write permissions are not required.)
Note that the device will often report abnormally high readings immediately after being plugged in, then settle down to a more reasonable number.
## Installation
ExCO₂Mini is [available in Hex](https://hex.pm/packages/ex_co2_mini).
If you haven't already, start a project with `mix new`.
Then, add `ex_co2_mini` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:ex_co2_mini, "~> 0.1.2"}
]
end
```
Run `mix deps.get` to pull ExCO₂Mini into your project, and you're good to go.
## Usage
```elixir
# Connect to the device and start reading data:
{:ok, reader} = ExCO2Mini.Reader.start_link(device: "/dev/co2mini")
# Subscribe to the Reader to start receiving raw data:
ExCO2Mini.Reader.subscribe(reader)
# Receive messages (do this repeatedly):
receive do
{^reader, {key, value}} -> Logger.debug("received #{key}=#{value}")
end
# Attach a Collector to the Reader to get data on demand:
{:ok, collector} = ExCO2Mini.Collector.start_link(reader: reader)
# Give it a few seconds to collect data:
Process.sleep(5_000)
# Now you should be able to retrieve CO₂ (parts per million)
# and temperature (degrees Celsius) data:
co2 = ExCo2Mini.Collector.co2_ppm(collector)
temp = ExCO2Mini.Collector.temperature(collector)
Logger.info("CO₂ = #{co2} ppm, temperature = #{temp} °C")
```
### Supervised Usage
If you want to set up a Reader and a Collector in a Supervisor, you can give them names and tell each to connect to the other. This will ensure that they continue to communicate even if one or the other is restarted:
```elixir
children = [
{ExCO2Mini.Reader,
[
name: MyApp.Reader,
subscribers: [MyApp.Collector],
send_from_name: true,
device: "/dev/co2mini"
]},
{ExCO2Mini.Collector,
[
name: MyApp.Collector,
reader: MyApp.Reader,
subscribe_as_name: true
]}
]
Supervisor.start_link(
children,
strategy: :one_for_one,
name: MyApp.Supervisor
)
```
Using `send_from_name` will ensure that the Reader sends messages using its `name` option — i.e. messages will look like `{MyApp.Reader, {key, value}}` — and `subscribe_as_name` will ensure that the Collector subscribes using its own `name` value (so the Reader can track it if it restarts).
See [ddco2](https://github.com/wisq/ddco2) for an example of this usage.
## Documentation
Full documentation can be found at [https://hexdocs.pm/ex_co2_mini](https://hexdocs.pm/ex_co2_mini).
## Legal stuff
Copyright © 2019, Adrian Irving-Beer.
Parts of this code are based on code and data from the ["Reverse-Engineering a low-cost USB CO₂ monitor" project](https://hackaday.io/project/5301-reverse-engineering-a-low-cost-usb-co-monitor). My thanks go out to Henryk Plötz, whose reverse engineering made this project possible.
ExCO₂Mini is released under the [Apache 2 License](https://github.com/wisq/ex_co2_mini/blob/master/LICENSE) and is provided with **no warranty**. This library is aimed at hobbyists and home enthusiasts, and should be used in **non-life-critical situations only**.