Edge Collective: DIY CO2 Monitoring


The following is a development notebook for constructing a DIY CO2 monitor.

Project Updates

2021-02-05 10:07:42

Update 05 Feb 2021


2021-01-30 08:54:11

Update 30 Jan 2021

Bayou-CO2 up and running.

Feedmaps prototyped. Backend needs work.

Pi set up as Bridge. Can store data locally on Pi without internet connection.

Heltec version, REV_F working.

MicroSD seen as most reliable and accessible way to set up wifi + Bayou credentials on device. Heltec difficult to set up this way. Pivoting to FeatherESP32 in next PCB design.

Next design: Feather ESP32-based, and designed as 'bottom plate' for a clear plastic enclosure (1591BT). Right-angle USB pointing down and buttons on bottom. (MicroSD on bottom too? Would allow for header to use Adafruit board if useful / option). Stand-offs for mounting on wall. If doing this, could also put LoRa on bottom, too. That way the SMT parts get soldered on one side, and can conserve space on other side.)

Lending library design is main focus. System that can collect data on-site. Can also think about 'sync', with replication of feeds into the cloud.

Pi as bridge allows for local data storage, and optional sync to cloud. Can use hotspot with ethernet jack (widely avail).

Same design could accomodate a Feather M0 LoRA as a remote node, with different firmware, taking credentials from microSD. Or the codebase could use ESP32 + LoRa. Might be easier to do that, with a software 'switch'. Not sure. Can prototype both ways.

Goals for Version 1

(Updated: 2020-12-09 08:31:32)

Key to assessment of work items:

Hardware + firmware

Data server

Client data viz / analysis

Science / calibration / validation

Goals for Version 2

User data viz / analysis workflow

Hardware + firmware

Science / calibration / validation

Update 2020-12-07

Hardware and Firmware

Latest accomplishments:

Next steps:


Latest accomplishments:

Next steps:

Data Analysis

Latest accomplishments:

Next steps:

2021-01-16 21:19:52

REV_E Parts list


More or less random bookmarks into the notes file, for reference:

2020 SEPT 29

Experiments with K30 from CO2METER.com

Online description of K30

K30 Datasheet

Needs 5V power minimum (actually, looks like it's best run at 6-9V); meanwhile, Logic levels for the UART are at 3.3V.

Useful info on logic levels / etc from the datasheet:

Table 1 from the K30 datasheet.

Meanwhile, though -- good advice on connecting to signals that run at higher voltage from JeeLab, here. Punchline -- can add a 1K resistor in series with signal as protection.

Figure 2 from the K30 datasheet.

Datasheet says: should avoid connecting analog and digital ground pins externally in order to avoid ground loops

Analog outputs.

Connecting to an Arduino

Via I2C

Connecting a K30 to an Arduino via I2C

This suggests using 6 to 9V input. (Might be good to upgrade the spec on the MCP1702 voltage reg so we can take > 6V input on the Mothbot). Needs to be able to provide 500mA. So: direct from battery power is likely best.

Notes on using a Feather

Schematic of the Feather M0 Lora.

Datasheet for the AP2112-3.3 voltage regulator used on the feather is here.

From the AP2112K datasheet -- 6V max allowed on Feather:

UART connection.


Note: Logic levels for the UART are at 3.3V.

Connecting a K30 to an Arduino via UART

UART connection.
First readings.
Blowing on the sensor and then letting it recover.

Edge Collective copy of the library for UART connection is here (replica of that provided by CO2 Monitor here).

SSD1306 Display

Guide here for hookup to Arduino UNO.

UART + SSD1306 Display

Example code here.

Remote LoRa CO2 Node and Heltec Gateway sending to FarmOS

Using a Mothbot to connect to the K30 sensor over UART and send via LoRa to a Heltec Wifi-LoRa gateway, posting to FarmOS.

Code for remote and gateway is here.

Mothbot remote node connected to K30 CO2 sensor.
Closeup of Mothbot.
Closeup of K30 CO2 sensor.
Heltec Wifi-LoRa gateway
Graphing on FarmOS


Would be nice to develop useful ways of connecting to some standard hardware (e.g. Feathers, etc).

CO2 and Greenhouses

Article on measuring CO2 in greenhouses:

Until recently, the vast majority of growers in the U.S. did not measure CO2 or use it to enrich their greenhouses. However, during the winter, CO2 levels can quickly become limiting in unventilated greenhouses full of plants on cold and sunny days. Over the past 10 years, we have also seen greenhouse growers seal up their greenhouses in an effort to control their heating bills during the winter. Other growers, especially in northern latitudes, have invested in supplemental lighting because of the numerous benefits, from improved quality and yields to reduced production time. An apparent result of tightly sealing the greenhouse is increased humidity and condensation. A not-so-apparent result of reducing air infiltration is a reduction of CO2 levels within the greenhouse below ambient levels found outdoors.

Oct 9 2020:

Maybe a good configuraiton is to have the sensor powered via a 7.4V rechargeable lith-ion, while the micro attached has its separate battery voltage?

oct 13 2020:

Recreating the prototype but using a Feather M0 instead ...

now we want to use Hardware Serial instead of Software Serial ...

We noticed a Twitter thread by Linsey Marr on Oct 8 2020 that references using a CO2 monitor to assess activity in a space re: COVID-19; they use the HOBO CO2 monitor pictured in Fig C below.

Fig C. HOBO CO2 Logger used to assess activity level / air turnover in a college gym.

Note: some power options (if plugging into the wall): use a 9V power wall wart, and drop down voltage to 5V; or use a 5V wall wart (more commong), and boost up to 9V.

If the latter, probably need to check on current (mA) requirements of the K30.

Offhand, seems like drop down is easier; boosting to 6V / 9V is a bit odd.

Feather Hookup Guide for K30

Fig A2. Feather M0 connected to a K30 sensor.

Feather firmware is here.

Wiring for test:

Fig A. UART connection on the K30. When connecting to the Feather, connect TXD (K30) to RX0 (Feather) and RXD (K30) to TX1 (Feather).
Fig B. Data from Feather, plotted in Arduino plotter utility. Data shows breathing on sensor at a particular time and and watching decay. Time interval unit is 2 seconds.

UPDATE: looks like the K30 can be powered by up to 14V. So a 12V boost, or power supply, could be an option.

Started by closing door, sitting next to sensor. At 150 time mark, opened door and left room. Then At 250 time mark, reentered room and closed door. At 280 time mark, started a conversation.

Cf. 'room_test.png'.

'room_test_later.png' -- had a phone call

'room_test_later_2.png' -- left room for a bit with door open, then emilie came back and worked with the door open.

Reference for typical / expected CO2 values

Nice discussion here, thanks to Laura P.

Other CO2 Sensors


Specifically mentions NDIR.

For sale on Banggood. Another option


Mentions infrared. This is the one that Craig used / that I have in my possession now.

For sale on Banggood for $20.

Goal as of 13 OCT 2020: get this up and running in parallel to the K30 and see how they compare with the 'ambient' test.

Nice article on testing out the Z19 on a Raspberry Pi.

Update 15 OCT 2020: Just found a fairly official-looking Arduino library for the MH-Z19 here by WifWaf.

In that repo they have some nice notes about calibration. The Z19 allows us to turn autocalibration off (which seems useful -- otherwise it is using the lowest reading in a 24 hour period as '400 ppm'). Would be good to experiment with this.

Also, here's another library for the MH-19 -- looks a bit older. Going to try the WifWaf one above for now.

Note that the WifWaf github MH-Z19 lib is already in the Arduino online Lib repo, can just install via Library Manager in IDE.

Update 15 OCT 2020: was able to get the WifWaf lib running on the MothbotV3. Radiohead + the library ends up generating a 'low memory' warning. This is fine; we'll likely end up using the Feather; also, we can pare down the full library to just generate raw values, likely.

Programming the Heltec Gateway

Guide to using ESP32 in Arduino IDE

Another guide from Sparkfun

Add this to Boards Manager:


Select 'Heltec Wifi Lora (v2)'

Programming with Feather

Add this to Boards Manager:


CO2 with K30 to FarmOS

Oct 14 2020

Posting CO2 PPM data from a K30 to FarmOS, measuring overnight from 14 OCT to 15 OCT 2020.

Turning off autocalibration in K30

This article mentions a technique, using their library.

CO2 with custom server

(TODO: set up using chappy-server as a model?)

15 OCT 2020 10:42 AM

K30 is autocalibrating, Z19 is not.

Ah -- looks like the K30 also can give temp, and RH! Cf the example here.

How to read the K30 via I2c app note here.

Ahhh here is a library for multiple params by CO2meter for the K30 -- boom.

need to modify their library so that it doesn't rely on SoftwareSerial (necessarily)

-- but first check whether we can even disable autocalibration?

Reading the K30 datasheet

Useful CO2meter guide to K30 ABC here.

i2c communication guide to K series sensors

-- looks like it can be disabled in EEPROM via I2C, at least ...

Nice reference on connecting a Teensy to a K30 here

Reference to a key application note re: K-Series eeprom setup here

-- need to email them, UART command lib is missing ...

15 OCT 14:00 -- Interesting link to the Yoctopuce V2, which uses a 'better sensor' than the K30, they claim ...

The K30-based yoctopuce-c02 is here

More about the yp-co2-v2 is here

Yp-co2 (K30) user's guide

K30 via i2c

this is the serious guide, here

simple i2c example here


The yocto uses the SCD30 -- listed for $54 on digikey

Here's the SCD30 datasheet

Arduino library here

And on github

annnnd the Sparkfun library has a 'disable calibration' settting here

Summary as of 15 OCt 2020 15:00

K30 seems outdated; won't trust it until we figure out how to turn off the autocalibration ... waiting to hear back from CO2 meter

MH-Z19 is also a bit older; can at least control the autocal ...

The calibration assumption with these meters seems to be that they use the lowest ppm value over some period and consider it to be 400 ppm -- assumes that all spaces end up getting 'fresh air' at some point in that period. For the K30, this is et to 7 days. Not sure for the other sensors.

Also: readings for NDIR are temp, humidity, and pressure dependent. My sense is that all the sensors measure these variables and compensate; the SCD30 also allows for feeding it the current ambient pressure and using it for calibration.

My current thought is the SCD30 would be a good one to get, along with an ambient pressure sensor.

OCT 16 2020

Example of an electrochemical CO2 sensor.

Really nice collection of references from co2meter.com

OCT 21 2020

Looks like the SCD30 can run off 3.3V, requiring max current of 80mA -- that's well within range of Feather LDO I believe!

SCD30 datasheet has the following table:

SCD30 handling and assembly guide

Electrical characeristics of SCD30.

Listing for th SCD30 on Amazon, here.

And on Digikey, here.

Note: should likely pair with a precision pressure sensor like the BME280 or better.

OCT 22 2020

CO2Meter note on calibration here

Calibration for the SCD30 sensor document here p. 7 / 10.

Calibration of the SCD30, via this document

Upshot: seems as though with the ABC algorithm, sensor needs to see at least 1 hour of fresh air daily. With the 'manual' mode, can run it for 2 minutes outdoors and press button saying 'calibrate' and set it to '400ppm'.
Seems like this latter mode would work best.

Assembly of SCD30

Assembly of SCD30 PCB, via this doc

OCT 23 2020

SCD30 Field Calibration

Field calibration guide for SCD30

Manual Field Calibration

Effect of 'forced recalibration' (FRC) of SCD30 as described in the SCD30 ield calibration guide
Automatic Field Calibration
Effect of automatic self-calibration (ASC) algorithm used in SCD30 as described in the SCD30 ield calibration guide.

OCT 24 2020

Might consider adding a high-precision pressure sensor to any SCD30 breakout board; the SCD30 can compensate for pressure if sent values directly. E.g. the BMP388 breakout from Adafruit.

NOV 12 2020

Quick task: Feather-based breakout for SCD30 + BMP388 or equiv.

Any other useful things to add?

Should we use the ESP32?

If we use Heltec, it could be a remote node or a gateway ...

That's an argument for using the Heltec ...

Looks like SCD30 can use i2c ... ... other sensors can use i2c (break it out!) or UART ...

which library does Sparkfun use?

SCD30 library and pinout

Sparkfun SCD30 library Ah, here's the Sparkfun SCD30 CO2 Library. They use i2c, great!

SCD30 pinout From the SCD30 datasheet:

Making a breakout

Pinout for BMP388, precision temp + pressure ...

Current thinking: make a place for the i2c oled displays, both the thin and the larger versions.

Ahhh ... BM390 has even greater precision, why not go for that. Looks like same pinout, in fact.

BMP390 Pinout

(Same as BMP380)

Question -- do we need the INT pin assigned to a feather pin?

Looks like it might only be for SPI -- see Adafruit description of pinout. In any case, not used in their libraries, so don't assign for now.

Feather M0 pinout

Adding a second UART to the Feather M0

Guide is here

They give an example with D10 as TX and D11 as RX. So, break out those pins.


Breakout REV A

Current breakout board is here.

2020 NOV 13

Lithium Ion battery that fits nicely inside of feather, here.

Sizing logos in Kicad, article here.

2020 NOV 14

Nice guide to trace width here.

Trace width calculator link here, and here.

Calculating trace width

Based on this link at OSHPark, the typical copper thickness for a 2-layer board is 2oz.


I think the CO2 board won't source more than 0.2 Amps.

Ah! Note that JLCPCB uses 1 oz copper by default. This means:

CO2 Motherboard REV A

Idea: develop footprint for K30 and Z19, to co-deploy the sensors and test them out.

On the other hand: nice to have a board that is smaller, that can connect to these other boards, but is ready to start deploying as its own sensor.

Here's a version (REV_A) that does the latter.

Now, need to ask again: can we turn off the autocalibration for the Z19 and the K30?

Z19, I believe it's straightforward -- need to review.

K30 -- here are the links sent via email from CO2Meter:

Screenshot of gaslab software from CO2Meter, showing serial interface to turn ABC off:

Turning off ABC in K30 via i2c (found in 'Communications Protocols Manuals', in the i2c folder. Specific document stored in our archives here.

Communicating with K30 via I2C + Arduino guide, here. Example below:

// CO2 Meter K-series Example Interface
// Revised by Marv Kausch, 7/2016 at CO2 Meter <co2meter.com>
// Talks via I2C to K30/K22/K33/Logger sensors and displays CO2 values
// 12/31/09
#include <Wire.h>
// We will be using the I2C hardware interface on the Arduino in
// combination with the built-in Wire library to interface.
// Arduino analog input 5 - I2C SCL
// Arduino analog input 4 - I2C SDA
  In this example we will do a basic read of the CO2 value and checksum verification.
  For more advanced applications please see the I2C Comm guide.
int co2Addr = 0x68;
// This is the default address of the CO2 sensor, 7bits shifted left.
void setup() {
  Wire.begin ();
  pinMode(13, OUTPUT); // address of the Arduino LED indicator
  Serial.println("Application Note AN-102: Interface Arduino to K-30");
// Function : int readCO2()
// Returns : CO2 Value upon success, 0 upon checksum failure
// Assumes : - Wire library has been imported successfully.
// - LED is connected to IO pin 13
// - CO2 sensor address is defined in co2_addr
int readCO2()
  int co2_value = 0;  // We will store the CO2 value inside this variable.

  digitalWrite(13, HIGH);  // turn on LED
  // On most Arduino platforms this pin is used as an indicator light.

  /* Begin Write Sequence */



  /* End Write Sequence. */

    We wait 10ms for the sensor to process our command.
    The sensors's primary duties are to accurately
    measure CO2 values. Waiting 10ms will ensure the
    data is properly written to RAM



  /* Begin Read Sequence */

    Since we requested 2 bytes from the sensor we must
    read in 4 bytes. This includes the payload, checksum,
    and command status byte.


  Wire.requestFrom(co2Addr, 4);

  byte i = 0;
  byte buffer[4] = {0, 0, 0, 0};

    Wire.available() is not nessessary. Implementation is obscure but we leave
    it in here for portability and to future proof our code
  while (Wire.available())
    buffer[i] = Wire.read();

  /* End Read Sequence */

    Using some bitwise manipulation we will shift our buffer
    into an integer for general consumption

  co2_value = 0;
  co2_value |= buffer[1] & 0xFF;
  co2_value = co2_value << 8;
  co2_value |= buffer[2] & 0xFF;

  byte sum = 0; //Checksum Byte
  sum = buffer[0] + buffer[1] + buffer[2]; //Byte addition utilizes overflow

  if (sum == buffer[3])
    // Success!
    digitalWrite(13, LOW);
    return co2_value;
    // Failure!
      Checksum failure can be due to a number of factors,
      fuzzy electrons, sensor busy, etc.

    digitalWrite(13, LOW);
    return 0;
void loop() {

  int co2Value = readCO2();
  if (co2Value > 0)
    Serial.print("CO2 Value: ");
    Serial.println("Checksum failed / Communication failure");

CO2 Motherboard Update NOV 14 2020

'Final' REV_A version (ordered on JLCPCB on 14 NOV) is here:

Repo for REV_A schematic and board file is here.

2020 NOV 16

Research paper on CO2 and COVID safety by Peng et al

Really nice research paper by Peng and Jimenez that yields CO2 thresholds for indoor activity, with thresholds based on activity / mask use / etc -- linked here.

Abstract from Peng and Jimenez 2020.

This is the key figure (Fig 2) to understand from the paper:

Figure 2. from Peng and Jimenez 2020.

An online aersol transmission calculator based on the paper is here.

The tweet broadcasting the tool is here.

The lead author on the paper, an expert on aerosol transmission, is here.

Some of the feedback on the paper & tool was from Linsey Marr, the NYTimes-quoted air expert on COVID transmission. Her Twitter profile is here.


Need to add buttons!! For calibration, and other navigation.

Sensiron SCD30 available on Amazon UK

NRF52 + LoRa wing setup --


2020 NOV 17

REV_B -- Based on Feather, adds buttons

REVB board 3D rendering:

REV_B KiCAD design files are here.

2020 NOV 18

Heltec version of CO2 board ... 'REV_C' ...

Aside -- interesting 'hiveyes' project using the Heltec, might have interesting code associated with it, here. Nice collection of github code here, including weight scales!

Interesting radio protocol here.

Radio protocols -- another way in which efficiency might be in tradeoff with legibility.

REV_C of board -- based on Heltec

Kicad design files are here.

Thread here on the battery connector type for the Heltec -- "Micro JST 1.25 mm".

CO2 Calibration via Gas Cylinder

Example of 1000 ppm cylinder here

Aranet: Bluetooth E-Ink CO2 Sensor

Product here

Manual here

Moteino M0

Product page here

Product guide here

IQAir monitor

Link on Amazon here.

GZair monitor for CO2

Link on Amazon here.

2020 NOV 23

Carbon Dioxide Board Rev_A

REV_A Boards have arrived in the mail. Assembly and initial code tests!

Sparkfun SCD30 i2c library is here.

First version with display, lora, screen, scd30 is here.

Associated gateway code is here.

Online data is currently posting here.

Quick indoor test of REV_A board.

Also took sensor outside for a few minutes. It fluctuated a lot. Seems like we're going to want to average readings over a minute or or more to get some stable value when the CO2 is low. Might have been due to wind. Might need to suggest that people get out of wind if they calibrate outside. Or, to tell folks to wait til the reading stabilizes before hitting calibrate. Or even have this happen automatically.


2020 NOV 24

Results of overnight test on NOV 23. Out of three people in apartment, two went to bed at around 8 PM, the final person at around 10:30 PM. One person (me) woke up and started using computer right next to CO2 sensor at 4:30 AM. Collecting data in this Bayou feed, generated these graphs as of 4:30 AM:

CO2 concentration in PPM, 2020 NOV 23 overnight.
Temperature in C, 2020 NOV 23 overnight.

Comment. Note the correlation between temperature and CO2, with co-occurring peaks around 12 AM and 1:30 AM. The temperature pattern likely due to the HVAC system. (The spike in CO2 and temperature at 4:30 AM are likely simply due to my presence near the sensor.) Unless the HVAC is in fact bringing in air with higher concentration of CO2, perhaps this indicates the range of fluctuation in CO2 reading due to temperature. Do we expect CO2 to rise with temperature for this NDIR sensor type?

Found nice reference for effect of temperature and pressure on CO2, here.

Key passage:

The size of the NDIR sampling chamber is fixed and is open to the atmosphere so that air can move in and out. As explained above, the number of air molecules in a given volume is affected by temperature and air pressure but not the concentration of CO2. At low pressures or high temperatures, there will be fewer air molecules in the sample chamber, so there will also be fewer CO2 molecules, even though the ppm of CO2 hasn’t changed. Fewer CO2 molecules “fools” the sensor into thinking that the CO2 concentration is lower than it really is. At high pressures or low temperatures, there are more air molecules in the sample chamber and more CO2 molecules, even though the CO2 concentration hasn’t changed. More CO2 molecules “fools” the sensor into thinking that the CO2 concentration is higher than it really is. Therefore a CO2 sensor calibration will only be accurate at one temperature and one air pressure.

This would suggest:

This fluctuation is due to pressure inside the apartment, when the HVAC system turns on? Now worth attempting to compensate with external pressure sensor.

Addendum. I've now replaced the above graphs so that we can see the readings from 0430 to 0530, during which time I sat close to sensor. Note that the temperature rose less than during some of the nightly spikes, but CO2 rose more, as one might expect given my proximity to the sensor. This perhaps leads to more confidence in the temperature-compensation of the SCD30.

Thoughts on calibration, and baselines. The key metric in the 2020 paper by Peng et al is 'PPM above baseline'. So, perhaps absolute calibration isn't really an important metric, here; more useful and interesting might be to establish a 'baseline', algorithmically; display it graphically; and allow the user to adjust based on their interpretation.

Key passage from page one of Peng et al:

Indoor CO2 has been suggested as a practical proxy of respiratory infectious disease transmission risk (8), as pathogen-containing aerosols and CO2 are co-exhaled by those infected (Fig. 1). Since background (ambient) CO2 level is stable and indoor excess CO2 is usually only from human exhalation, measurements of indoor CO2 concentration by low-cost CO2 sensors can often be good indicators of infection risk and suitable for mass deployment (9, 10).

Use of microphones to detect ambient activity

Nice tutorial on measuring sound levels using the MAX4466. This might be the way to go if we're going to use ambient audio data to determine in-room activity.

Tutorial on using the auto-gain mic, which might be even better ...

This fancy microphone amplifier module is a step above the rest, with built in automatic gain control. The AGC in the amplifier means that nearby 'loud' sounds will be quieted so they don't overwhelm & 'clip' the amplifier, and even quiet, far-away sounds will be amplified. This amplifier is great for when you want to record or detect audio in a setting where levels change and you don't want to have to tweak the amplifier gain all the time.

Design. Using a simple, auto-amplified microphone in this context seems useful. The raw data can be presented online, and used in an attempt to discern baseline thresholds. No algorithm needs to be applied at first; or, the user community can supply the algorithm.

This leads to an instrument in the following Designer PCB configuration:

Total: $72

This can also be accomplished by a more DIY Version:

Total: $98

Likely best to produce this latter version immediately, and then take time, if available, to make the inexpensive version.


This is an open hardware project in the realm of home-based IOT; a highly-contested area around privacy. In this case, for example, a microphone levels can probably serve a useful proxy for indoor occupancy status. Usually, this would lead to anxieties about privacy. But because we can produce this device in an open hardware manner, we can avoid an entire class of such concerns. (Not all such concerns: there's still the possibility that other surveillance software made it onto the device).

By making this a FOSS/H project, we allow more eyes onto the design to evaluate.

Switch on microphone.

Ability to deploy mic without CO2, if just want to monitor activity levels in an area.

Ability to deploy CO2 without mic, in order to secure privacy.

MAX9814 Adafruit module

Listing for product is here.

Schematic is here.

Note on confounding factors

From page 2 of Peng 2020:

If there are no other significant CO2 sources/sinks (e.g., gas/coal stove and pets/plants), i.e., if indoor excess CO2 (relative to the background outdoor level) production is only due to human exhalation and its loss is ventilation, similar quantities for CO2 can be expressed as follows (see Materials and Methods for the derivation)

Gas stove or pets can be a source; plants can be a sink.

Indeed, looks like I may have seen this effect using a propane stove on Nov 24 2020, as per experiment above.

24 NOV 2020 Update @ 14:30

CO2 (PPM). Note: made lunch around noon on Nov 24 (gas stove). Left house around 12:30 / 12:45 on Nov 24.

Microphone pinouts

MAX9814 Auto-gain audio board from Adafruit.
MAX4466 adjustible audio board from Adafruit.

2020 NOV 24 Update 22:10

Arrived back home at 5:30 PM Nov 24th. Interesting that the ambient CO2 decreased in our absence to a value lower than overnight in the apartment with us sleeping there.

2020 NOV 25

CO2 (PPM) measured on Nov 245th through morning of Nov 25th. Spikes on Nov 24th at 7:30 AM, 10:30 AM, 12 PM, and on Nov 25th at 8 AM, are perhaps due to use of propane stove for cooking. Apartment was unoccupied on Nov 24th from about 12:30 PM until 5:30 PM.

2020-11-27 17:20:40

Snapshot from the Bayou feed. Left house around 9 AM on Nov 26th. Visitors likely in house, late morning of Nov 27th. Returned home a little before 5 PM, and started using gas stove.

Light sensors

Vishay light sensor here.

Simple, cheap analog light sensor breakout here.

BH1750 here,seemed to be recommended for ambient light sensing ... but difficult to solder. Note though that this seems widely available on Amazon as breakout boards. This description also indicates that it's a good candidate for this application; and in fact, the leads don't look too small.


MEMS mic from Adafruit, the SPW2430

Looks like: use the electret verison for the DIY solderable verison; use the SPW2430 or similar for custom PCB.

MAX4466 from Amazon:

Nice post on comparing MEMS and Electret microphones.

Tutorial on measuring sound levels with the MAX4466 by Adafruit here.

Design Review

2020-11-27 20:18:07


Light sensors:

REV_B + MAX4466 Experiment

REV_B appears to work!

Now testing microphone ...

Connecting analog out of mic to A0 on REV_B (one of the button pins) ...

Running overnight on Nov 27th with mic sampling of 10 sec ...

Test code is [here](

Data will appear here.

2020-11-28 04:22:39

My impression is that this mic will require additional signal conditioning to pick up ambient noise; perhaps this can be done with an op-amp and a potentiometer that allows experimentation; or maybe a light sensor is the best next step. Or maybe auto-gain is best, the idea being that it will attempt to acquire any signal. That said, I'd think that 'max gain' on this system would do the trick, if that would work. All depends on the circuit and the mic.

MAX4466 Datasheet.

Data from the Bayou feed, overnight Nov 27th -- Nov 28th in CSV format has a snapshot here. This analysis is necessary because the current graphical display in Bayou is configured to who only every 10th data point; we'd like to see the higher-density data.

Snapshot of mic data from the Bayou feed. Woke up at 5 AM. Note that pattern of sampling shown is a bit odd. Need to dive back in an look at how data is captured and how it should be averaged.
Higher sampling rate of mic data from the Bayou feed. Working to convert this to proper dates (see below) ...

Aside: converting unix timestamps in Sheets

Formula for converting unix timestamp to date in Excel / Sheets is discussed here; if the timestamp is in cell 'A1', the formula for the date is:


Analysis of Initial CO2 and Microphone Data

CO2 and Mic data from the Bayou feed. Microphone data is "highest p-p amplitude over 10 sec interval". Note -- entered room with sensor around 4:30 AM. Generally mic data seems to precipitate rise in CO2 level. At some point gas stove was used; from this data, I would surmise around 6:40 AM, but unsure. Need to track this next round.

Enclosure options

115 x 90 x 55mm for $10 w/ transparent screw cover here.

Popular 200 x120 x56 mm for $15 w/ transparent screw cover here

5.9 x 3.9 x 2.8inch w latching cover here

Would be nice to have 'wings' for mounting ...

This one has wings, here.

In fact, seems to be part of a pretty standard and well-rated series, here

In particular, the 4.5"x3.3"x1.4"(115x85x35mm) size looks good, for $10. But: maybe too flat to drill holes for cables. And will require fairly large PCB.

From comments, the comparison is between Awclub and LeMotech on Amazon, favoring LeMotech for quality. Likely to find some analysis of sizes and design in hobby projects online (or better: datasheets) given how popular the brands are.

Plan: first assess how large the project will likely be by laying out some PCBs, and order an enclosure.

Review of best projecte enclosures here

Apparently the 'wings' I'm referring to are termed 'ears'.

E.g.: for the 4.5 x 3.5 x 2.68 inch(115 x 90 x 68 mm) 'ear' Lemotech version, the PCB is essentially 84 mm by 89 mm.

This might be a good case size to shoot for. I think I can accommodate it. A larger PCB might be expensive, anyway.

Datasheet for this enclosure is here.

Need to accommodate a USB cable.

Alright: let's lay out a PCB for testing, and if it looks plausible, order one of these.

Note that the 6.2"x3.5"x1.8" version of LeMotech has a nice drawing by a user. Also has same price as smallest version.

Suggestion to make panel mounting oneself.

This is in keeping with previous ideas.

From what I can tell online, the most effective & inexpensive / adaptable approach to enclosures might be:

The reason given online for this is that the inexpensive enclosures are often made from 'recycled molds' that have poor tolerances. So it really isn't a great idea to design a custom PCB for them. Rather, lasercut inexpensive (ideally, drillable, as backup) mounting plates.

Large, Flat LeMotech enclosure

Outside Size (approx.): 6.2"x3.5"x1.8"(158mmx90mmx46mm)/(LWH); Inner size (approx.): 5.9"x3.3"x1.6"(151mmx84mmx42mm)/(LWH)- - (Allowable Error: 2mm); Screw Thread Size: M4

Lemotech enclosure, 6.2 x 3.5 x 1.8 inch (158 x 90 x 46 mm).
Customer-provided CAD drawings for Lemotech enclosure, 6.2 x 3.5 x 1.8 inch (158 x 90 x 46 mm).

Smallest LeMotech enclosure

Outside Size (approx.): 4.5"x3.5"x2.68"/(115mmx90mmx68mm)(LWH); Inner size (approx.): 4.3"x3.3"x2.44"/(111mmx86mmx62mm) (LWH)- -(Allowable Error: 2mm); Screw Thread Dia.: 4mm/0.16"

Lemotech enclosure, 4.5"x3.5"x2.68"/(115mmx90mmx68mm).

2020-11-28 15:37:00

Overall framing / todos.

2020-11-29 21:52:45


Jupyter dashboard via voila -- gallery of examples

gesis notebooks, here

guide to voila, here

Dashboarding options in Jupyter discussed here

2020-12-01 13:41:41

REV_D -- ESP32 + RFM95 SMT Version

2020-12-01 16:17:24

Continuing research for REV_D ...

Quahog circuit (ESP32 + RFM95) ...

Some changes that need to be made to the circuit:

Heltec pinout (ESP32 + RFM95) ...

Heltec schematic

Feather ESP32 Schematic

REV_C Notes

Misjudged the header spaceings on the Heltec -- too far apart by one row!

REV_D Notes

MMBT2222 NPN Mosfet datasheet -- it's 'BEC' -- 1: BASE, 2: EMITTER, 3: COLLECTOR

BMP388 / 390

Adafruit guide to BMP388 is here.

Breakout schematic:

2020-12-01 20:45:59

REV_D Initial Pass

2020-12-02 20:41:42

Upshot -- the SPW2430 mic is weak w/out an amplifier -- should check out tutorial for how to add it when doing SMT version ...

Meanwhile, light sensor BH1750 tutorial is here

Install hp_BH1750 library via Arduino IDE ...

firmware that adds the light sensor is here

Resultant data feed here

Adding an amplifier to the SPW2430

For reference, Eagle CAD for max4466 is here -- can likely use the amp setup they have ...

2020-12-03 08:25:40

co2 sensor seems to have stopped last night? and reset on m0 didn't reset it -- needed to power cycle -- do we need a mosfet on it?

if we use esp32 for mic, do we need to worry about analog performance / drift?

Should SEL be floating to ground (or tied to ground) on SCD30? https://forum.sparkfun.com/viewtopic.php?t=48325

issue where bh1750 library hangs here.

tried co2 + bh1750 -- co2 freezes

can't reset, co2 still 'frozen'

changed firmware to remove bh1750, but kept bh1750 on board, co2 freezes

then removed wires of bh1750, no freezing yet

I wonder if it's an 'address' issue with the bh1750? can check. info on the module i'm using is here

BUT: light sensor is of questionable use for now. better perhaps to have breakout for i2c.

real next steps:

Seems like the max4466 board avail on amazon (here) is fairly identical to that sold by Adafruit. wonder if the op-amp is similarly set up.

So, design:

i like how explicit the mic on the co2 sensor is ... and it's an analog reading -- if it's removed, just get 'zero' for analog measurement.

that might be the place to start. simplify the design. part is avail on amazon, alternative to adafruit.

don't even need a switch -- just remove the part.

Nice feature: basic board that can be produced with SMT parts; then, add adafruit boards for pressure and/or mic as one likes.

Adding BMP388 functionality to REV_B

Tutorial on Adafruit here.

Actually, confusing way to do the i2c / spi ... not sure how to hook up to Feather's i2c ...

Shifting to Sparkfun library here ....

which leads to the library here

Nice feature: allows for use with ESP32, has special code for that ... (maybe just picks particular pins?)

2020-12-03 10:10:13

Looks like BMP388 code is working (using the lib from MartinL1, 'BMP388_DEV', here).

Also: having the device on a Feather LoRa, using a gateway, is a nice system -- can deploy several all over a building, or across a campus, even if no wifi available.

University systems have issues using wifi. This way, can use where there is wifi. Also: get one device registered on wifi network, rather than several. (Typically, for IT on campus, would need to register every one).

Also note: might be useful to have a PC with a heltec and a python script. That way the PC can be registered on the network, the heltec can be placed at a height.

Also: might be good to have a microsd on the heltec.

Need to test soon in a university / high school class setting.

Can we get serial input to a chromebook this way?

2020-12-03 15:58:47

Features to add:

Another reason to do esp32 + rfm95 is to allow for access point configuration of device

2020-12-04 22:21:45

Red is mic data, blue is CO2. Spreadsheet is here, based on feed here (pulled on eve of Dec 4).

2020-12-06 09:54:24

Feather ESP32 remote wifi sensor ("REV_B")

All systems go!

Feather ESP32 scd30 code for "rev_b" is here

Heltec ESP32 + LoRa remote wifi sensor ("REV_C")

SSD1306 with the u8x8 library tutorial here

List of u8x8 fonts here

Arduino code for heltec-based "rev_c" with bmp388 is here

without bmp388 is here

Max4466 on ESP32

Adafruit tutorial on Max4466

2020-12-06 14:42:04

Fixed the microphone issue with the Feather ESP32 -- seems to be necessary to refer to A0 by its gpio number for feather esp32 -- i.e., "26" for A0.

Updated code for REV_B Feather ESP32 is here

Posting data from REV_B with Feather esp32 ('wifi sensor' mode) here.

2020-12-06 15:08:54

Parallel tests:

REV_C board (heltec) feed here

REV_B board (with Feather ESP32) feed here

2020-12-06 19:05:45

Jupyter plotting csv file tutorial here

Another nice guide here

plotting two data traces on the same graph:

ax = df1.plot()

2020-12-06 20:02:10

Comparing two scd30 sensors

Procedure: Sensors were placed side-by-side. No effort was made to calibrate manually. They had been operating for only a few seconds before data was collected; so the automatic calibration algorithm (which begins at 7 days) had not been in operation. Next attempt will involve manually calibrating both in same fresh air conditions, and looking at resulting behavior.

Using two SCD30 sensors, side-by-side. Left: "REV_C" board using Heltec 32 Wifi LoRa v2 as micro. Right: "REV_B" board using Feather ESP32 as micro.
Comparison of two side-by-side SCD30 CO2 sensors for a given time range. Jupyter notebook used in the analysis is here.

Tweet about aerosol transmission here.

Aerosol / virus researchers

SCD30 Pressure Correction and Calibration Disable

Sparkfun SCD30 library is here, and has several relevant examples:

SCD30 datasheet

Forced calibration of SCD30

See 1.3.7 (p. 7) of document:

SCD30 interface description

For implementation, look at Sparkfun library and follow procedure for temperature / altitude compensation.

E.g. altitude compensation code begins here

//Set the altitude compenstation. See 1.3.9.
bool SCD30::setAltitudeCompensation(uint16_t altitude)
  return sendCommand(COMMAND_SET_ALTITUDE_COMPENSATION, altitude);

Can we set this up with a button? Would be nice if it works mid-loop ... test with ESP32?

ESP32 GPIO interrupts guide here

Fork of Sparkfun library here

Experimental feed is here

Update: the library already includes the functionality!

setForcedRecalibrationFactor(int co2_concentration_ppm)

the 'calibrate' button on rev_c is pin 36

ESP32 debouncing a button w/ interrupts, here

The ultimate debouncer from Hackaday

Heltec pinout discussion

Following debounce here

2020-12-06 21:37:07

Meanwhile, verify that the forced calibration works. Expectation: if we do it after a few loops, the current CO2 value will suddenly appear to be whatever we force it to be.

Force calibrate seems to work!

Code (still working out a button debounce routine) here

overnight feeds as of 2020-12-06 22:13:47:

feather esp32 feed

heltec (calibrated)

2020-12-07 09:35:29

Plan update

2020-12-07 10:23:27

Further reading on temperature / other compensation for the SCD30, "Low Power Mode for the SCD30"

Observation: when force calibrating the sensor outdoors in much lower temperature and assuming 410 ppm, it recovered inside to < 400 ppm. This may be because of temperature effects. There is a temperature compensation function for the sensor. It requires an external temperature reading for calibration. This might be done with a 1-wire temp sensor attached to the device.

So, advantages of the pvos device:

2020-12-07 10:37:03

Blog on use of SCD30 here

TODO: need to find field calibration guide for SCD30.

SEEED wiki on SCD30

SCD30 design-in guidelines

I believe the airflow isolation issue is the reason for seeing such strong fluctuations of measurements when outdoors in wind, and is a strong argument for designing an enclosure:

2020-12-07 11:53:18

Resurrecting the React code ...

React sparkines library here

How to trigger a popup in Leaflet, here

React Leaflet documentation

Stack overflow for interacting with leaflet in React here -- with associated fiddle

Victory Chart

pswoodworth's code for poll / leaflet

How to use React Leaflet

Using Leaflet for non-map images

Nice tutorial on using leaflet to zoom into images -- has some nice tiling programs!

Using leaflet to pan and zoom a big image

first go at non-geographical imagery

Based on: "using leaflet with non-geographical imagery" tutorial.

Code in 'trial.html' here

leaflet map in a flexbox layout here

See 'side.html' here:

Leaflet guide to non-geographic maps here

Using CRS in React-Leaflet here

Example with imageoverlay and react-leaflet here

Note: "reg-leaf" branch of spark-leaf repo is a working example.

Jamming on inserting code from here into my current setup

hmm, this approach seems simple here

support for non-geographical maps here

2020-12-07 21:23:59

'clicknav' is a working branch.

fetching data in react using hooks here

another article here

much nicer guide here

working with 'livedata' branch of spark-map currently ...

using react and fetch here

2020-12-08 10:58:47

interactive viz of data on map

nice leaflet grid layer code for displaying lat / long here

Nice leaflet grid layer here

2020-12-08 12:39:52

running p2p-farm-server locally, branch: 'mappin'


reference putscript_local.sh for the appropriate keys and to add more data

SVG sparklines here

keeping popups open in leaflet here

intro to leaflet here

add and remove leaflet circle on click here

assigning ids to markers in leaflet here

adding horizontal lines in chartjs here

above is 'mappin' branch of p2p-farm-server on gitlab

2020-12-09 17:39:11

modfiying leaflet icon on mouseover here

leaflet icon resize

nice working example of buttons and overlap and highlighting here.

references for covid 19




great writings collected here: https://twitter.com/JuliaLMarcus

battery-powered datalogging, for use on e.g. planes? export to csv ...

2020-12-10 11:08:32

Curated Twitter list of air quality / covid / science

Link here

Key organizing tweet by Jose-Luis Jimenez, here and here. Jimenez group here.

Jimenez group listing here

Aranet4 listing here

Article covering Jimenez int'l org around air quality and covid here

Online presentation here

2020-12-10 13:42:11

note on next steps:

2020-12-10 17:44:16

SCD30 Cross-comparison with force calibration

Note on experimental setup. Code is set up to broadcast every 90 seconds; on third round, it force calibrates to 410 ppm; there is a parameter named 'forced' that is '0' initially and then '1' after forced calibration. Both devices were reset simultaneously, hopefully they will be relatively in sync when force calibrated. need to check difference.

Update: no, better to force calibrate in beginning. Send value right after force calibration, then reset to 0.

2020-12-10 20:21:52

2020-12-10 22:03:01

Note that the orange line is the FeatherESP2, and tracking the 'forced' parameter indicates that the device rebooted and then re-force calibrated to 410 ppm. Not sure why it rebooted -- perhaps the power supply on the Feather is insufficient to handle the SCD30, or the memory? Note that the readings were more variable for the Feather prior to the reboot.

2020-12-10 22:12:26

Added legend, and the 'forced' parameter, to make it all more explicit. Here, the red line is the Feather32 data, the blue is the Heltec. The accompanying 'forced' data are shown, multiplied and shifted to show on scale.

New experiment: restart code, but swap the SCD30 modules.

2020-12-10 22:18:31

Update: swapped the scd30. heltec didn't start up at first. realized that i placed the scd30, was shorting something. so there may be some odd data out of the heltec now. if there was something wrong with the scd30 module associated with the feather, it's on the heltec now.

Note -- if this immediate divergence is 'real', it could indicate that small variations in air flow are very important / and/or that one oughtn't to worry about fluctuations on order of approx 50 ppm.

Reasons it might not be 'real' -- one of the sensors is underpowered b/c of a different micro ... the scd30 sampling rate is too high, or we're force calibrating too soon ... others?

2020-12-10 22:45:58

Ah -- after careful readjustment inside enclosure, looks like they did coincide more closely (or could be fluke) on restart (last restart / force calibration before the '80000' mark.) Will now monitor to see whether one of the devices exhibits odd behavior.

Now that I've switched scd30 modules ... if the data from the Feather32 still exhibits odd behavior, then my guess would be that the problem is the power supply / memory of the Feather32. If the data from the heltec exhibits odd behavior, then the problem may lie with that particular scd30 module.

2020-12-10 22:53:13

Last two resets are after readjusted enclosure.

2020-12-11 06:14:27

Results from overnight, after initial force calibration on both sensors (as per above description):

Systematic difference (red climbs faster) is perhaps due to placement in box / closer to airflow opening.

Plot of difference between the two traces above:

SCD30 Field Calibration Guide

SCD30 Field Calibration Guide here

Effects of forced recalibration (from guide):

Effects of automatic calibration (from guide):

2020-12-11 08:03:52

Updated scd30 comparison:


2020-12-11 09:25:16

Jupyter Lab setup

Notebook for above analysis is here

2020-12-11 13:54:30

2020-12-11 22:33:39

Revisiting the 'map' interface code

p2p-farm-server/public/console.html is the latest code connected to the p2p-farm-server, which does floorplan side by side with the charts.

the route to visit is here.

It's determined in p2p-farm-server/routes/index.js

meanwhile, the code that connects buttons and highlights leaflet markers is here.

2020-12-12 10:50:11

console update

Video of attempt at interactive code here, and below:

Relevant code is in 'console.html', here; the routes portion of the server that handles that page is index.js, here.

Note: was able to resolve CORS errors when prototyping locally by simply referencing the '' address rather than 'localhost'.

Inspirational map flood network viz here (link to actual viz seems to be broken).

2020-12-12 14:04:25

Revisiting mic

Adafruit max4466 is here.

Typical Amazon cheaper product is here

Dimensions of board seem to be about (width x height) (15 mm x 22 mm).

qwiic connector, right angle

qwiic connector, vertical

listed on adafruit here. "JST SH 4-pin" -- 'micro' / 'vertical' version.

tactile switch side / horizontal

amazon listing here

For now: break out A0 and A1 pins to do the button measurement separately on a breakout if need be (to externalize the control, avoid interacting with scd30).

Aside: nice neobit project

battery for heltec

micro li-ion board on Amazon here -- 'jst 1.25 connector 2 pin'

Size: 8.52540(mm)

2020-12-13 09:55:51


mini pushbutton switch -- tall via sparkfun

10 mm tall.

How tall is a typical header?

Assortment of pushbuttons here

Omron B3F datasheet here

need to swap out 'dual' switch for a single ..

Guide for qwiic connectors

Discussion here


Redo for easier hand soldering?

Qwiic adapter hookup guide

2020-12-14 13:27:09

enclosure options

link to smaller enclosure

Datasheet for smaller enclosure is here

2020-12-14 21:52:32

PCB ordering for REV_E

Github repo for REV_E is here

Zipped Gerber files for REV_E are here

Next steps

2020-12-19 08:07:40



JST SH 4 pin micro -- vertical, here

horizontal (as placed on rev_e) here

or as listed on sparkfun (horizontal) here

2020-12-19 13:18:40

uFL connector

adafruit uFL connector here

looking at feather m0 lora pcb for uFL connector reference here


BMP3XX adafruit firmware on github here

BMP3XX adafruit hardware design files on github here


BMP390 datasheet here

Adafruit BMP390 schematic:


BMP388 datasheet here

Adafruit BMP388 schematic:

Question: do we need to add a power supply to board? Seems to be a common way of keeping the power supply clean for the pressure sensor chip.

Reference: here

Looks like we should add a regulator. Default to using the Adafruit part, change if something else seems better.

Adafruit uses AP2112K-3.3 for the BMP390 breakout (more recent breakout). This also seems to be used for the feather.

Look to see if it's also used for the Feather ESP32 -- and what its specs are -- if it can source sufficient current for the full CO2 board (which are ...?)



AP2112K-3.3 on Digikey and associated datasheet

Looks like it can provide 600 mA.

max input 6V

Assume SOT-23-5 package on Adafruit

Battery charger

Also add MCP73831.

Feather M0 MCP7831:


Do FTDI board separately? yes b/c DTR might be needed

Reset and GPIO0

TODO: Need also to break out the reset and other button, in case ftdi cable someone uses doesn't expose dtr ...

Buttons -- use SW_Push symbol ... with which SMT buttons? use adafruits?

these are the KMR2 buttons from the Feather and etc. datasheet is here

look to see how adafruit did it with the huzzah board

Ah, there we go -- GPIO0 is floating:

Calibrate / other buttons

TODO: add the side-mounted through-hole buttons that ordered on Amazon, and that were present on REV_E

JST connectors

Add connectors for micro and reg lithium ion? Might be nice for folks used the world of feathers.

Using standard Adafruit one (2-pin JST PH)

as well as a micro one -- JST SH -- SM02B-SRSS-TB(LF)(SN) -- digikey link here


this would simplify things.

Q: Possible to solder? Look at Feather ESP32 schematic / footprint.

Maybe this is a separate project -- make an ftdi header board.

Need to decide on nice microUSB footprint. SMT would be nice, and fine for this context -- don't need through-hole. feather esp32 part should be fine. see if you can source them on digikey (or which smt parts are easy to source).

Adafruit microUSB part is the 4UConn 20329 v2, datasheet here

Link to Adafruit microUSB part here

MicroUSB B with KiCad footprints:

the microUSB device used on the riffle is here; datasheet is here

above left: 10104110; above right: 10104111

some optoins for footprints in kicad:

A recommended Amphenol part is here

Filtering / decoupling

TODO Need to add caps from all relevant sub-circuits:

Possible to add footprint for USB chip and allow FTDI?

Adafruit Feather ESP32 eagle files on github

Feather ESP32 schematic:

CP2104 subcircuit:


the microSD card used on the Riffle 0.1.8 is here

2020-12-19 19:00:53

TODO: double check pin order on JST connectors ...

DMG3415U p-mosfet used in power circuit for Feather ESP32 here; datasheet; SOT23;

to check orientation / pin assign for the pmos as part of the power circuit, here's what we see on the feather esp32:

Diode -- MBR120 -- SOD-123FL -- datasheet

Note: used KiCAD 123F rather than 123FL

now I have all of them avail. seems like sod 123FL is the most pop part on digikey. but 123 and 123FL are avail. see here

2020-12-19 20:37:04

latest updates to board design ("REV_D") are here

note: need to review and see if there are any remaining changes.

might try to place a microSD on the board and guess at a CS pin; but also break out SPI + optional CS pins. If SPI conflict, might be able to start by only doing LoRa (SPI) OR microSD (SPI) on bus in any given firmware.


if add a smt mic, add a switch otherwise: maybe just make it an optional DIP add-on ...

2020-12-20 08:21:38

rather than replicate the mosfet on the power supply, maybe just have one at the intake?

alright -- emulate feather 32 instead of heltec. we know that the circuit works, and it's the same esp32 module, with same pins avail.

iterate to fancier version of batt meas circuit.

check against tinypico for power circuit

nice reference for esp32 pinouts and which pins to use here

default spi pins on esp32 for lora here

Hog 32 schematic:

using the arduino ide + esp32 + sd card here

update: heltec uses gpio5 for lora sck; feather esp32 uses gpio5 for sck; so that's fine. default to using feather esp32 pinouts.

pins 34,35,36,39 are input only. use these on buttons.

ref for using sd card featherwing with feather esp32 here -- cs is on gpio33

BMP388 wiring / connections

nice reference here

Qwiic pin arrangement

Adalogger featherwing pin arrangement

(mimic in rev_d)

Advice regarding microusb ground

Reference here

SOD123 oddness?

TODO: Look into changing footprint ...

Pad sizes

2020-12-22 09:41:59

for low power tests -- look up tinypico schematic

schematic here

and in our own repo here

key part is the power subcircuit:

This is the regulator they are using on the board here

and this is the mosfet here

analysis: looks like we've got essentially an identical circuit; they make a different choice of mosfet, but we can probably dial that in easily ....

2020-12-22 10:00:06

battery voltage meas reference on jeenode here

TODO: check reset subcircuit -- match feather

2020-12-24 05:04:43

Test of the co2 board "rev_e"!

Used firmware here

bayou data feed is here

2020-12-27 08:57:35

Enclosure arriving today linked to on Amazon here

example enclosure from pac-tec here

free samples here

the OD43 looks good here; drawing here

2020-12-27 15:55:50

Update: small enclsoure arrived. The shape is a bit awkward, and it was anyway broken. If going with plastic enclosure, might be better to find another / a specific manufacturer.

Rev_f was an attempt to re-spin rev_e in order to fit inside New idea: 3d print a nice enclosure, and then also design a cardboard one. Run them side-by-side for a few days to see any differences. Humidity might be a factor; but can line inside with tape, and humidity is supposedly compensated for.

2020-12-27 20:24:24

openscad ...

designing a box with openscad

3d printed enclosures with openscad here

2020-12-28 07:28:38

Test of REV_E system starting here

UPDATE: Looks like it never really went above initial baseline (which started around 8:10 AM on below graph):

Aside: nice info on openscad shapes / language here

2020-12-28 11:52:02

Making an enclosure for Rev_E using OpenSCAD

Description of process of making an enclosure for Rev_E (kicad board files for RevE) in the below video:

The associated scad file for this video is:

Some additional files / information:

Dimensions for PVOS CO2 Rev_E (KiCAD board files are here.
OpenSCAD rendering of an enclosure protype. Scad file is here.
STL file for cover is here.
STL file for bottom is here.

Separately rendered cover and bottom are here:

2020-12-28 19:52:34

Craig has now revamped the scad file considerably, allowing everything to be measured in 'pcb coordinates' much more readily.

Latest branch is "ver1d_holes", and the associated scad file is here.

Latest version ("ver1d") of OpenSCAD enclosure.

2020-12-28 20:34:24

Meanwhile, working on box enclosure:

Latest version 'box enclosure template' for REV_E. Scad file is here

2020-12-29 10:59:16

2020-12-29 13:53:04

latest file with holes for screen, mic, buttons is here -- still need to add USB and lora holes

maybe should make cover a bit narrower to accomodate the bend ends ?

2020-12-29 16:59:44

REV_E Cardboard enclosure update

2020-12-29 20:13:52

File is here (note that it's in the 'cardboard' branch)

REV_E 3D printed enclsoure update

File is here.

2020-12-30 14:16:53

Optimizing cardboard designs

The current design worked out better with a thinner cardboard box from Amazon, that has 'A3' and 'FLX' printed prominently on it, and which also had some graphics printed on it. Saving that as "a3_flx.scad" in the 'cardboard' branc.

Going to try also to optimize for the thicker (but I think more standard) Amazon box that has "Z12" and "120" printed on it, saving as 'z12_120.scad'.

2020-12-30 14:55:05

Set up 'router-style' connection on rev_e ...

'heltec_router.ino' ...

2020-12-30 15:03:18


TODO: check button status on rev_e -- is "A" connected to LED pin?

Basic button check ...

Buttons check out. Pin "A" is gpio37, Pin "B" is gpio36.

Jupyter analysis


WiFi setup with ESP32

Nice tutorial here

Ahh -- this is the code I'd found that worked nicely -- from hieromon, here.

Arduino WiFi module description here

captive portal here

wifimanager for esp32 here

or maybe better library https://diyprojects.io/esp32-test-wifimanager-library-manage-wifi-connections/#.X-99TnVKjVM

this seems powerful -- not sure how to use though!


https://github.com/tonyp7/esp32-wifi-manager/ looks like a great option

back to trying https://diyprojects.io/esp32-test-wifimanager-library-manage-wifi-connections/#.X--CfHVKjVM

documentation for wifi manager here

note: seems that we want the 'development' branch of wifimanger for esp32 -- as per instructions here

tutorial on using wifimanager (with esp8266, but should work here) -- https://diyprojects.io/esp32-test-wifimanager-library-manage-wifi-connections/#.X--CfHVKjVM

2021-01-01 15:48:48

OKAY! working wifi configuration (basic) at https://github.com/edgecollective/co2-remote-and-gateway/tree/rev_e_wifi_config/rev_e/firmware/wifi_sensor/wifi_config_basic_scd30

2021-01-01 18:13:05

migrating from arduinojson5 to 6 article here

2021-01-01 19:17:36

okay, current candidates are: wifimanager (dev branch), and hieromon.

latest attempt at getting it to work (which req'd upgrading the ArduinoJSON code) was here: AutoConnectWithFSParameters_bayou

customization on wifimanager looks a bit hairy.
l hieromon might work better re: customization.

trying more with hieromon now ...

for autoconnect, looks like we want to consider autoreconnect to determine behavior if device needs to connect to wifi again. link here: https://hieromon.github.io/AutoConnect/adconnection.html

2021-01-01 19:49:31

Here's a thread on how to delete credentials --


2021-01-01 20:31:46

This code is working fairly nicely!


Document this tomorrow first thing.

It displays the AP to visit, then once connected, displays the IP.

Need to collect custom paramters ...

2021-01-02 10:45:37

autocnnect wifi connect sending to bayou -- sort of an mvp -- https://github.com/edgecollective/co2-remote-and-gateway/tree/rev_e_wifi_config/rev_e/firmware/wifi_sensor/AutoConnect_Elements_display_scd30

2021-01-02 11:16:49

basic landing page functionality here: https://github.com/edgecollective/co2-remote-and-gateway/tree/rev_e_wifi_config/rev_e/firmware/wifi_sensor/AutoConnect_Elements_display_scd30_landing_page

2021-01-02 12:26:43

Getting data form AutoConnect -- https://hieromon.github.io/AutoConnect/achandling.html

2021-01-02 13:40:42

use of snprintf: https://joequery.me/code/snprintf-c/

2021-01-02 14:45:33

A nice basic MVP, here:


It allows for configuring wifi. The Bayou credentials are set via 'credentials.h' (requires Arduino IDE). There's an informative landing page.

This would work for a version where the Bayou feed is flashed before the device is shipped, or by the user.

For a user-config version, a nice starting point might be the code here:


... where one might use the '/elements' page to capture Bayou feed credentials (and maybe set the measurement interval).

TODO: set the measurement interval in the config file.

Some more todos:

Initial rollout:

Does the SMT need to be part of the rollout?

Add an opencollective tier for:

2021-01-02 18:35:56

u8x8 fonts here: https://github.com/olikraus/u8g2/wiki/fntlist8x8

2021-01-02 19:17:19

Two button interface video demo here

Code here: https://github.com/edgecollective/co2-remote-and-gateway/tree/button/rev_e/firmware/wifi_sensor/two_buttons

NOTE: LED D1 doesn't seem to work -- perhaps value of resistor?

2021-01-02 21:01:25

Idea: measure every X seconds; average these values; PUT every Y*X seconds so that the PUT interval is 5 or 10 min or more. The averaging will help smooth out the noise. Every measurement, can blink the LED (optionally) and update the screen. Indicate on screen when have sent data online.

Also: can embed videos & other 'heavy' material in the ESP32 landing page by pulling it from online such that it only shows up once there's an internet connection to the outside world ...

2021-01-03 10:54:43

cap_params seems to work alright ...

working on cap_params_load ...

retrieving files from SPIFFS -- https://techexplorations.com/blog/esp32/blog-esp32-how-to-retrieve-a-file-from-the-spiffs/

2021-01-03 11:55:47

arduinojson read file -- https://arduinojson.org/v6/example/config/

arduinojson read array -- https://arduinojson.org/v6/api/jsonarray/

SPIFFS read and write examples https://www.esp8266.com/viewtopic.php?f=29&t=8194

this is how i want to reference an element of the array i think https://arduinojson.org/v6/api/jsonarray/subscript/

2021-01-03 13:12:57

Okay, this version of the code uses a file, elements.json, on the SPIFFS filesystem of the esp32 to configure things; and it can be modified by the esp32 as well.


2021-01-03 13:29:44

Getting closer to capturing parameters data:


2021-01-03 16:51:47

params_fuller_FS is where it's at!

warning regarding dynamic memory usage in micros here: https://arduino.stackexchange.com/questions/1013/how-do-i-split-an-incoming-string

2021-01-03 19:02:50

This is getting really close now:


Need to get it to make some measurements; but basic interface seems to be in place now.

2021-01-04 08:52:08

setting the AutConnect menu items https://hieromon.github.io/AutoConnect/apiconfig.html#menuitems

Captive portal IP address if captive doesn't work:

configuration of autoconnect portal here

customizing menu further here

IDEA: be able to modify 'force calibrate co2 value' from AutoConnect

this is what I ended up using to customize the menu

resulting in this commit for param_fuller_FS


2021-01-04 13:30:08


free enclosure from pac-tec:

interesting free enclosure option:

PCB size (from design drawing above):

Nice plastic enclosure -- hammond -- https://www.newark.com/hammond/1591btcl/enclosure-multipurpose-pc-clear/dp/50H6344?gclid=Cj0KCQiAlsv_BRDtARIsAHMGVSaA4dpnCVFMKYrILm7lfwtSkz8Ny4HzIejUIkhMuzIm0uqSNvsL_kIaAiK8EALw_wcB&mckv=sFz5B29IT_dc|pcrid|434136793431|plid||kword||match||slid||product|50H6344|pgrid|100464451426|ptaid|pla-917181830621|&CMP=KNC-GUSA-GEN-Shopping-NewStructure-Enclosures-Racks-Cabinets

Some nice options

Serpac 032C


Serpac 032C

detachable wall mount! https://www.serpac.com/accessories/wall-mounts.aspx

Serpac wall mount


This could actually be cool -- 'main board' on left, 'proto board' on right

--- but it's $20 :)


hammond tiny enclosure -- https://vetco.net/products/hammond-1551ltbu-translucent-blue-plastic-enclosure-3-15-in-x-1-58-in-x-0-59-in?gclid=Cj0KCQiAlsv_BRDtARIsAHMGVSbv12vGAESWYlcDZyyMR1AF3k45esmKYOVDSHDajJhLA6uLqX9A1j0aAqqiEALw_wcB

hammond clear enclosure -- https://www.digikey.com/en/products/detail/hammond-manufacturing/1591BTCL/1090769?utm_adgroup=Boxes&utm_source=google&utm_medium=cpc&utm_campaign=Shopping_Boxes%2C%20Enclosures%2C%20Racks&utm_term=&utm_content=Boxes&gclid=Cj0KCQiAlsv_BRDtARIsAHMGVSbbCxZ7-93S11wYu57zYg54tGOrZ8DzqvXXx9VZYEySfmGR_M6y7EwaAtUCEALw_wcB

octopart enclosure listing here

bud industries BT-2723 here

hammond 1551LTBU here

hammond cheap boxes

multipurpose translucent hammond boxes here

accessory plastic flanges avail!!

hammond 1591S --

hammond economical enclosures here

hammond 1591STCL on digikey here

really cool series, with accessories! here

allows mounting of pc boards horizontally within enclosure here

shenzen enclosure here

this is worth ordering for testing -- enclosures for $4 ea here -- https://www.alibaba.com/product-detail/IP65-plastic-transparent-electronic-enclosure_60787051803.html

top candidates:

hammond 1591STCL / 1591BTCL serpac 032C

listing for that whole hammond line is here

avail on amazon!! here

1591BTCL avail via amazon here

1591BTCL datasheet is here

hammond page for 1591btcl is here

the whole 1591 series is listed here

1591BTCL is avail for $5.10 ea at Hawk Electronics here

1591STCL here

1591DTCL -- would fit the REV_E board!

meanwhile I think I can probably redesign and fit the 1591STCL or 1591BTCL (whichever is cheaper)

1591STCL -- $10.50 1591BTCL -- $7.80 1591DTCL -- $12.02


1591BTCL (datasheet) -- this is the target to design for.
1591DTCL (datasheet) (octopart) (digikey) -- this is what I can buy to house the REV_E enclosure.

1591DTCL avail via Powell electronics here

DTCL arrives on jan 25 - ish here

If I do the BTCL, I'll need to find a clever way to include the battery ... maybe on top somehow.


$10 aluminum enclosure bud insdustries -- https://www.digikey.com/en/products/detail/bud-industries/AN-1302-A/5804534?utm_adgroup=Boxes&utm_source=google&utm_medium=cpc&utm_campaign=Shopping_Boxes%2C%20Enclosures%2C%20Racks&utm_term=&utm_content=Boxes&gclid=Cj0KCQiAlsv_BRDtARIsAHMGVSZDrdL__T4EZEguqhJTtaaFs6oxlLmh0ItZ9ZZeMTFqdDHsmJ5U4goaAiZJEALw_wcB

1591STCL here

2021-01-04 22:12:14

accessory flanges for 1591 series here --

digikey listing for the flange for the 1591DTCL here

1591BSFLBK on newark here

adapter card pcb for 1591 series:

1591DTCL enclosure diagram here

associated slot pcb mountings diagram here

associated plastic flanges listed here

Likely should order some on Digikey tomorrow.

Interesting that it gives us some room for prototyping

Epidemiologist around rapid testing here

TODO: add the flange to the digikey order and order tomorrow

flange for the DTCL seems to be the 1591FDBK (digikey drawing)

Aside: gorgeous hammond enclosure 1590B die-cast aluminum (amazon)

2021-01-05 11:46:04

to get:

update: gray is on backorder. going with black.

2021-01-05 18:37:37

this seems to be key -- how to set up the captive portal IP address -- need to check whether this works on a laptop https://hieromon.github.io/AutoConnect/apiconfig.html#gateway

2021-01-05 19:07:15

Finished the AutoConnect switch-over of endpoint names -- now use 'bayou_settings' instead of 'mqtt_setting'.

Resultant working code is here (note branch): https://github.com/edgecollective/co2-remote-and-gateway/tree/cap_params/rev_e/firmware/wifi_sensor/params_fuller_FS_endpoint

2021-01-06 16:27:47

1591 enclosure guide for pcb here

might use a clear lid with a pre-flanged enclosure -- look here

2021-01-06 16:33:46

Black 'B' enclosure with a flange here

direct link for pc board adapter here

and dimensions for pcb board adapter here

catalog page for 1591 series here

looks here as though the 'C' enclosures come between 'B' and 'D' (surprise) -- hammond

also: C is just slightly larger than B, it seems

here are the C dimensions pdf -- and on amazon and digikey

2021-01-07 11:36:19

Document from Hammond re: the proper PCB size for the 1591B series here: pdf | dxf file | dxf file with dim

heltec dimensions

2021-01-07 14:08:27


particular commit here:


2021-01-07 15:07:44

Update: Pin 34-39 on the ESP32 are not capable of output -- that's why pin 39 wasn't working as an LED control.

looks like scd30 could use a 2.5 mm screw, ish; the height of the screw would be about 8 mm. so can guess at a standoff size perhaps.

nice material heltec here

full heltec tech specs here

does look in the schematic that there's a battery divider already in place -- see discussion here

interesting code for heltec from a lot of perspectives re: optimal use of esp32, includes battery measurement here: https://github.com/HelTecAutomation/Heltec_ESP32/blob/master/examples/ESP32/ADC_Read_Voltage/Battery_power/Battery_power.ino

pin 21 is external battery control -- low, ON --

special pins on esp32 here

pin 12 must be low during boot

2021-01-07 20:33:35

PIR sensor here

just need 3V, GND, and an input pin ... maybe add a screw terminal?

"sh1.25" is perhaps the search term for relevant batteries on aliexpress here

2021-01-08 11:54:39

Rev_F board submitted to JLCPCB, order Order #: Y12-2489114A // W202101090100951

board files github commit here

zipped gerber files in particular here

2021-01-12 14:40:22

2021-01-14 12:54:10

2021-01-15 11:25:38

Feed Name: "asdfasdf" Feed Public Key: 9816e2df7cc14d64698d7012859080757780c73f22213bd1 Feed Private Key: 7e633222f381a99170e370ea7476b43662507a5352077ade Feed Home Page: http://data.pvos.org/co2/data/9816e2df7cc14d64698d7012859080757780c73f22213bd1

TODO: add a download from the feed page (CSV?)

2021-01-15 12:26:46

Hammond flanged enclosures here

Main plastic enclosure page for Hammond here

1557 series

Vented sensor enclosure! here

2021-01-15 21:52:47

Latest firmware attempt is here. Acquires actual CO2 values & uploads them to Bayou-CO2

Test feed on Bayou-CO2 'loft' is at http://data.pvos.org/co2/data/09b3f0239025e03c386b3f3ccfeba5501f95b8eff0ec9358

2021-01-17 05:04:02

Loft test feed continues: http://data.pvos.org/co2/data/09b3f0239025e03c386b3f3ccfeba5501f95b8eff0ec9358

Notes on feed above:

jan 16

jan 17

Note that it seems that when I walk around a bit and go upstairs to loft huffing and puffing, there's an initial spike; the co2 calms down when i start to settle and work at computer quietly. then level decays further when I leave.

UPDATE: after refreshing feed, not sure this is true; the 'spike' isn't that much higher than what is perhaps 'noise'; the CO2 level does seem to be fairly stably higher when I'm up in loft.

Question: I wonder why there's an apparent dip below 'baseline' 6 PM to 830 PM on Jan 16? Maybe the doors to house were open a bit? interesting if we can show that baseline shifts considerably when crack open doors (experiment to be done)

2021-01-17 08:12:24

Just re-entered loft w/ coleman now ...

went back down, then camb back around 8:30 ...

2021-01-18 11:59:52

Working on pulling in parameters ... looks like this is how I did it here:


2021-01-18 12:06:20

Requirements in Arduino IDE for CO2 monitor based on ESP32 ...

IDE setup:


2021-01-18 12:49:59

Test feed here: http://data.pvos.org/co2/data/cbb8d444591def61d4e59f9b53d3193dd7724a9d8599c6ee

2021-01-18 13:54:57

Now reading in parameter file and displaying CO2 value with this commit: https://github.com/p-v-o-s/co2-monitor/commit/39c589e08763c8f280da3e49c05ae70d059a7791

Feed is here: http://data.pvos.org/co2/data/cbb8d444591def61d4e59f9b53d3193dd7724a9d8599c6ee

2021-01-18 14:10:36

Now show network config on button press https://github.com/p-v-o-s/co2-monitor/commit/5f05b084ba1b026370a0f2adb9492b0d187b2205

NOTE: should try to do everything with non-blocking code. This button approach currently delays for 3 sec. Could instead check every loop for whether enough time has passed, and whether should display which info.

TODO: implement this; also factor out display functions.

2021-01-19 04:57:51

Got weird error message -- result seemed to be no wifi connection, but loop still ran and measurement was made / screen updated every measurement interval:

E (52119735) wifi: esf_buf: t=2 l=76 max:32, alloc:32 no eb, TXQ_BLOCK=0

Really useful post on strings and esp32 and memory here

Looks like free heap is okay.

New test feed is here: http://data.pvos.org/co2/data/3897755c6379d00bbb1d622827b1ffd1ba6a0579802044c9

The current version of the code is here: https://github.com/p-v-o-s/co2-monitor/commit/af6c57182ef2486cf87aedc404f5fca257c330d0.

TODO: Reading in measurement interval from param file initially still not working (fix).

TODO: We should implement a watchdog that looks to see if successful post and/or connection and resets if not -- the error message I was seeing might be related to the wifi, apparently

TODO: Should also change the plotting style in Bayou-CO2 to not use bezier ...

2021-01-19 09:26:43


ESP32 power req's ...

Observation -- looks like heap stabilizes ...

getFreeHeap(): 250128
Measurement recorded

getFreeHeap(): 250128
Measurement recorded

getFreeHeap(): 250128
Measurement recorded

getFreeHeap(): 250128
Measurement recorded

2021-01-19 09:34:25

Get calibration code working ...

TODO: add force calibration value to the Bayou settings

TODO: add field to database indicating whether force calibrated in the last round ...

TODO: pull out configuration values as 'config' file (or put in json param file)

2021-01-19 10:40:54

Looks like by default, SCD30 sensor measurement interval is 2 seconds ... and can't go lower.

SCD30 datasheet reference p 10 of https://media.digikey.com/pdf/Data%20Sheets/Sensirion%20PDFs/CD_AN_SCD30_Interface_Description_D1.pdf

Just checked -- in fact, it does work to ask if there is new CO2 data available -- that gives us a delay of about 2 sec.

2021-01-19 10:49:03

Added calibration procedure with this commit: https://github.com/p-v-o-s/co2-monitor/commit/68c467baa1c6b8c20b4b76a5eb5f6a89d55c9508

2021-01-19 10:56:50

Fixed an interface bug with canceling forced calibration ...

Now, after pressing the calibrate button, in any case we drop into a 'firstLoop' meausurement, so that we make a measurement, display it, and send it. Probably a good feature anyway to have a way to send a value immediately. Might want to indicate graphically that data has been sent ("200" on top right of screen or something)

Also looks like the sensor needs at least a few seconds to warm up (check datasheet) ... maybe we should check for startup and display 'warming up' and show measurement every few seconds ..

2021-01-20 05:48:45

Stopped working overnight:

[HTTP] GET... failed, error: connection refused
getFreeHeap(): 250108
[HTTP] GET... failed, error: connection refused
getFreeHeap(): 250108
[HTTP] GET... failed, error: connection refused
getFreeHeap(): 250108
[HTTP] GET... failed, error: connection refused
getFreeHeap(): 250108
[HTTP] GET... failed, error: connection refused
getFreeHeap(): 250108
[HTTP] GET... failed, error: connection refused

-- is this Bayou, or the monitor?

UPDATE: answer -- it wasn't Bayou.

Pressed reset, and it just worked. Need to look into this as a bug; but this is another reason to set up a 'reset' if we don't a good connection to the server.

Ah -- it could be that the IP address changes overnight.

Good thread on watchdog style approach here: https://github.com/espressif/arduino-esp32/issues/653

More on this here: https://github.com/Hieromon/AutoConnect/issues/292

This might be the approach to take: https://github.com/Hieromon/AutoConnect/issues/292#issuecomment-757340418.

Skeleton code here: https://github.com/Hieromon/AutoConnect/issues/292#issuecomment-756634645

There is a patched release here: https://github.com/Hieromon/AutoConnect/issues/292#issuecomment-759202689 that might address the issue, and apparently release v1.2.3 will fix it?

Another nice post about dropping the wifi here: https://rntlab.com/question/wifi-connection-drops-auto-reconnect/

oooh -- and it offers some auto-restart code ... will try that ...

implemented in the 'restart' branch here: https://github.com/p-v-o-s/co2-monitor/tree/restart/co2monitor

2021-01-20 10:47:23

CORS and associated issues explained here

2021-01-20 11:00:02

Ideas discussed w/ Mike:

Bayou / deployment ideas:

Firmware ideas:

Hardware ideas:


2021-01-20 11:08:20

How to upload and display an image in NodeJS here: https://stackoverflow.com/questions/15772394/how-to-upload-display-and-save-images-using-node-js-and-express

General impression I'm getting: store image files on file system; store their filenames / references in the relational database.

Oh nice -- can use ImageMagic in NodeJs -- see this link here: https://stackoverflow.com/questions/12539918/get-the-width-and-height-of-an-image-in-node-js

Or you can probe the image size without a full download here: https://gitehub.com/nodeca/probe-image-size

One interim solution is: host your own image somewhere, and we can display feed data on top of it via URL ...

How to start a nodejs project here: https://philna.sh/blog/2019/01/10/how-to-start-a-node-js-project/

2021-01-20 11:40:26

Trying to work in this repo here: https://github.com/edgecollective/floorplan

This is the file that seems to have been the demo file I was playing with around mapping: https://gitlab.com/dwblair/p2p-farm-server/-/blob/mappin/public/console.html

Handling CORS here -- good guide; and:

good guide here, which leads to:

2021-01-20 15:24:42

Follwing this example here

Guide to pug here: https://www.sitepoint.com/a-beginners-guide-to-pug/

2021-01-20 16:57:33

Good start on plotting data in separate Node server here: https://github.com/edgecollective/floorplan/commit/607816a05848093a471966e0b9dd00c1cab90733

2021-01-20 20:38:45

Latest: try this link:

Some layout details here: https://coder-coder.com/display-divs-side-by-side/

Latest attempt is at this commit of floorplan in the url-load branch, here: https://github.com/edgecollective/floorplan/commit/4972382b4982f34b75a60b5f8026a180a1591daf

2021-01-20 20:59:49

Ongoing test feed is here: http://data.pvos.org/co2/data/3897755c6379d00bbb1d622827b1ffd1ba6a0579802044c9

2021-01-22 11:22:08

NDIR reference circuit

May be very similar to one used in SCD30 ...

"Complete Gas Sensor Circuit Using Nondispersive Infrared (NDIR)": link: https://www.analog.com/media/en/analog-dialogue/volume-50/number-4/articles/complete-gas-sensor-circuit.pdf

Mike B. comments on the SCD30:

Looks like a lamp at one end, and two legs are the two wavelengths - sensing, and reference; 75mA when measuring implies about 70 Ohms for that lamp.

NDIR refrence circuit for Alphasense CO2 Sensor

Link here: http://www.alphasense.com/WEB1213/wp-content/uploads/2016/01/AAN_202-04.pdfe

-- 2021-01-22 14:28:56

Design Review w MB

2021-01-23 11:52:42

Current case for REV_E ... 1591BTCL

2021-01-25 11:25:35

v0.1-alpha release of the firmware for REV_F!


2021-01-25 19:14:15

Added more info to the screen!

2021-01-27 07:46:09

Two devices:

ESP-1cfe posting to: http://data.pvos.org/co2/data/a00aed3265bf99e1784168ac9b1b509f30adfe9d00a2918d


ESP-2c7e posting to: http://data.pvos.org/co2/data/e9d7a2df343e8e6d0bf6c169011be8721ee9c24707ad7347

2021-01-27 09:24:36

SCD30 enclosure app note https://www.google.com/url?q=https://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/9.5_CO2/Sensirion_CO2_Sensors_SCD30_Design-In_Guidelines_D1.pdf&sa=D&source=hangouts&ust=1611842158712000&usg=AFQjCNE3z7ACuQZWf6VPmSG4CB_wEYk5Fg

2021-01-27 19:57:10

2021-01-28 08:21:57


2021-01-28 14:59:42

Article on airborne covid and CO2 montoring https://www.aol.com/article/lifestyle/2020/08/12/the-best-ways-to-reduce-the-risk-of-covid-19-indoors/24589315/

2021-01-28 15:28:17

2021-01-28 17:49:17

Adding microSD functionality to the Heltec ...


First get the libraries ...

Maybe it's possible to talk to SCD30 i2c over OLED i2c (as did on Quahog)? see https://github.com/HelTecAutomation/Heltec_ESP32/blob/master/examples/SD/SD_Time/SD_Time.ino

Ah, SD card might require resistors! See answer here: https://stackoverflow.com/questions/57454066/how-to-use-2-spi-devices-lora-and-sd-card-on-esp32

Also this info here -- looks like it can get dug out! http://ldsrc.blogspot.com/2018/02/micro-sd-card-for-esp32.html

2021-01-29 11:19:51

Switching over to Feather ESP32 ...

Arduino SD Card library + Feather breakout ... https://learn.adafruit.com/adafruit-adalogger-featherwing/using-the-sd-card

Adafruit microsd breakout board

Trying Examples > SD > Cardinfo

Note: important code for multiple SPI buses (for use later when doing microSD + lora): https://github.com/jonashoechst/ttgo-lora-sd

works ...

1591 Page on Hammond 1591BTCL Listing on Digikey Enclosure datasheet with screw positions

from datasheet

horizontal cover inside lip: 107.7 horizontal screw distance: 98.3 horizonal span (screw, inside lip): (107.7-98.3)/2 =

vertical screw distance: 48.4 vertical cover inside lip: 57.8 vertical span (screw, inside lip): (57.8-48.4)/2 =

sit inside enclosure

horizontal span: 106 mm horiz screw dist: 98.3 horiz screw center to edge: (106-98.3)/2 = 3.85

vertical span: 56 mm vert screw dist: 48.4 vert screw center to edge: (56-48.4)/2 = 3.8


top left: 3.85,3.8 top right: 3.85+98.3, 3.8 = 102.15,3.8 bottom left: 3.85, 3.8+48.4 = 3.85, 52.2 bottom right: 102.15, 52.2

USB "up angle"

Listing on amazon

Pi as Bridge





2021-01-29 17:12:36

deleting partitions using fdisk


This worked nicely: https://www.nayab.xyz/linux-tools/partitioning-using-fdisk.html

Showing progress while zipping: https://unix.stackexchange.com/questions/179563/when-i-use-zip-how-can-i-display-the-overall-progress-without-flooding-the-comm

Back up raspberry pi image:

sudo dd bs=4M if=/dev/sdb of=pvosPi.img status=progress

Zipping it afterwards:

zip -qr - pvosPi.img | pv -bep -s $(du -bs pvosPi.img | awk '{print $1}') > pvosPi.img.zip

2021-01-30 10:20:43

2021-01-30 16:30:53


Adding additional SPI buses https://github.com/espressif/arduino-esp32/issues/1219



2021-01-30 21:24:20

Working setup!


2021-01-31 09:13:44

Converting a board to a footprint https://forum.kicad.info/t/converting-board-to-footprint/2781/5

2021-01-31 17:08:28

M3 nylon standoffs amazon here

2021-01-31 17:50:52

Initial version of REV_G!


2021-01-31 19:55:55

Wiring up a microSD https://components101.com/misc/microsd-card-pinout-datasheet

Featherwing microsd https://cdn-learn.adafruit.com/assets/assets/000/044/116/original/feather_schem.png?1500667618

Feather schematic & pintouts https://cdn-learn.adafruit.com/assets/assets/000/041/630/original/feather_schem.png?1494449413

2021-01-31 20:15:51

The code that worked! (?) https://gitlab.com/p-v-o-s/co2/co2monitor-firmware/-/blob/master/v0.1-alpha/feather_esp32/feather_esp32_lora_sd_u8x8_scd30/feather_esp32_lora_sd_u8x8_scd30.ino

// SD uses 'regular' SPI pins on Feather ESP32:
#define SD_CS 33
#define SD_SCK 5
#define SD_MOSI 18
#define SD_MISO 19

// LoRa uses a newly-created SPI bus:

#define LORA_IRQ 15
#define LORA_CS 14
#define LORA_SCK 26 //A0
#define LORA_MOSI 21
#define LORA_MISO 25 //A1
#define LORA_RST 27

U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8(/* clock=/ 16, / data=/ 17, / reset=*/ 39);

SCD30 on 'regular' i2c for feather esp32: SCL: 22, SDA: 23

display on SCL: 16, SDA: 17

maybe add qwiik for both?


2021-01-31 20:29:41

First pass at pin assignments; double check!

Test button functionality ...

Add DIO1 for LoRaWAN ability?

Button pin assignments?

RESET pin choice for display (no wiring to do for library ... maybe U8X8 can avoid a reset pin? Or what pin do we assign in order to avoid conflicts?)

Add label / pinout / description for Adafruit microSD card on back

Hirose microSD part DM3D-SF on Digikey: https://www.digikey.com/en/products/detail/DM3D-SF/HR1941CT-ND/1786515

2021-02-02 17:08:26

Jupyterlab on a Raspberry Pi https://medium.com/analytics-vidhya/jupyter-lab-on-raspberry-pi-22876591b227#:~:text=Install%20Jupyter%20Lab,to%20install%20jupyter%20lab%20later.&text=Install%20jupyter%20using%20pip3.

Jupyer Hub on an RPi https://towardsdatascience.com/setup-your-home-jupyterhub-on-a-raspberry-pi-7ad32e20eed?gi=b0e66a9b10f7

The script-based approach to installing Jupyter! https://github.com/kleinee/jns

Another nice approach: https://morioh.com/p/93349454d65a

2021-02-03 05:18:10

2021-02-03 05:08:58

ESP32 and wifi access point https://www.google.com/search?q=esp32+can%27t+connect+to+pi+as+access+point&oq=esp32+can%27t+connect+to+pi+as+access+point&aqs=chrome..69i57.8176j0j7&sourceid=chrome&ie=UTF-8

ESP32 and wifi access point 2 https://www.esp32.com/viewtopic.php?t=18928

ESP32 and RPi connection without internet connection https://raspberrypi.stackexchange.com/questions/107647/esp-8266-and-raspberry-pi-communication-without-an-internet-connection

Update: just tried connecting my Heltec to my Pi using the identical image, without having the ethernet connected, and: "wifi?" but as soon as I plugged the ethernet back in, it connected. Googling now, this is a known problem: ESP32 doesn't like to connect to Pi as isolated AP. I think people have found a fix.

Suggestion to use MQTT here https://github.com/nhonchu/mqttspooler

Setting up a Raspberry Pi as an access point https://learn.sparkfun.com/tutorials/setting-up-a-raspberry-pi-3-as-an-access-point/all

Setting up a Pi as an access point in a standalone network -- solid instructions, here: https://github.com/SurferTim/documentation/blob/6bc583965254fa292a470990c40b145f553f6b34/configuration/wireless/access-point.md

Todo: follow instructions here on fresh Pi image install.

2021-02-04 09:04:21

M.B.'s data from overnight, using a REV_E and a Pi w/ Bayou-CO2 installed locally!

link on google sheets

2021-02-04 12:57:13

looks like syntax is:

var sql = "select * from user order by id desc LIMIT "

2021-02-04 15:11:18

comparing timestamps in postgresql



2021-02-05 10:43:17

Radiohead LoRa on ESP32 Heltec here:


Adafruit Radiohead example https://learn.adafruit.com/adafruit-rfm69hcw-and-rfm96-rfm95-rfm98-lora-packet-padio-breakouts/rfm9x-test

Arduino array length https://www.arduino.cc/reference/en/language/variables/data-types/array/

2021-02-05 13:12:57

Basic lora receive and parse (not yet POST) here:


2021-02-07 11:04:31

low power mode of scd30 https://www.mouser.com/pdfdocs/CD_AN_SCD30_Low_Power_Mode_D2.pdf

2021-02-09 12:26:06

Rev G BOM here: https://docs.google.com/spreadsheets/d/1lVheEod6zCzNCYa6XvAfB3fSmFhtaZ6GWjAGM3Qgw9o/edit#gid=970277542

Rev_G gerbers on Oshpark here: https://oshpark.com/shared_projects/B5Xvlckj

2021-02-09 19:58:22

Create the feed online here: http://co2data.pvos.org/

Arduino firmware is here: https://gitlab.com/p-v-o-s/co2/co2monitor-firmware/-/blob/master/releases/v0.4-alpha.zip

Examples (of individual feeds):



2021-02-11 17:31:12

1591 btcl http://www.hammondmfg.com/pdf/1591B.pdf

good thread on pcb hole sizes / placement https://www.eevblog.com/forum/eda/m3-screw-drill-diameter/

Depends how accurate are the hole positions are in what you are mounting it to. You want accurate size on one side and oversize on the other to allow for tolerance. 3.5mm would be a generally normal size for an M3 mount, but M3.5 on both pieces may get too sloppy, so you'd normally do 3.2mm on one and 3.5 on the other.
If it's just a general purpose mount hole with no specifiiic 'other bit', use 3.5mm

3M Command hooks -- metal

3M Command hooks -- plastic

2021-02-11 19:58:23

2021-02-12 09:58:30

2021-02-12 20:38:52

common hole / tap sizes:

M2 spacers on amazon

2021-02-12 21:25:40

Submitted to jlcpcb! Order: Y15-2489114A

Files: https://gitlab.com/p-v-o-s/co2/co2monitor-hardware/-/tree/838dbbc5dcd8af392ac3b86d49a4e15efe28e0f8/REV_H

2021-02-12 21:30:58

Updated code for REV_E and REV_F (Heltec) to show public key on screen here: https://gitlab.com/p-v-o-s/co2/co2monitor-firmware/-/tree/b0f7bae152fd3fedaaca335b2e49ac72dcf17830/v0.4-alpha/pvos_co2_wifi_pubkey

Test code for REV_G (Feather ESP32; should work on REV_H too) here: https://gitlab.com/p-v-o-s/co2/co2monitor-firmware/-/tree/40179ca69b689f22f4f3d207cea9c0f9568a5edf/v0.4-alpha/rev_g

2021-02-13 10:23:28

QR codes:


Added to feedmaps:


Added to bayou-co2:


download canvas https://www.purplesquirrels.com.au/2019/10/saving-a-canvas-element-as-an-image/

2021-02-14 11:14:43

canvas to pdf https://stackoverflow.com/questions/23681325/convert-canvas-to-pdf

2021-02-25 10:52:39

Code for watchdog timer for esp32 here: https://github.com/espressif/arduino-esp32/blob/master/libraries/ESP32/examples/Timer/WatchdogTimer/WatchdogTimer.ino

2021-02-27 14:23:17

Going to resurrect the 'lora mesh' idea ...

nootropic design lora mesh: https://nootropicdesign.com/projectlab/2018/10/20/lora-mesh-networking/

q: can we make radiohead lib work with sd card on same spi bus?

can the feather m0 work on a rev_h board?

simple radio control of stuff remotely as per nu vu ?

2021-02-27 19:53:43

basic lora mesh working on both heltecs and a feather: https://github.com/edgecollective/lora-mesh/tree/master/co2/simple_a

one specifies the 'target' node, and one's node id ...

would be nice to have a switch on the remote nodes to change node id

might use feather based board as gateway for now ...

As of Feb 27, here's what we see at A2:

The story is that there is a heater that turned off on Feb 24th, and turned back on around 3 PM Feb 25th ...

2021-02-28 12:07:50

blog post on mesh networking: https://nootropicdesign.com/projectlab/2018/10/20/lora-mesh-networking/

Idea: we can have the nodes mesh, and use a 'test network' to visualize. We can add a 'next hop' field to the database, as well as a 'last rssi' value, and a 'node id' field. so then we'll have:

node id next hop id rssi to the next hop

we can then start to visualize these networks using a similar approach

2021-02-28 13:08:51


bool RHRouter::recvfromAck(uint8_t* buf, uint8_t* len, uint8_t* source, uint8_t* dest, uint8_t* id, uint8_t* flags)
    uint8_t tmpMessageLen = sizeof(_tmpMessage);
    uint8_t _from;
    uint8_t _to;
    uint8_t _id;
    uint8_t _flags;
    if (RHReliableDatagram::recvfromAck((uint8_t*)&_tmpMessage, &tmpMessageLen, &_from, &_to, &_id, &_flags))
	// Here we simulate networks with limited visibility between nodes
	// so we can test routing
	if (
	    // This network looks like 1-2-3-4
	       (_thisAddress == 1 && _from == 2)
	    || (_thisAddress == 2 && (_from == 1 || _from == 3))
	    || (_thisAddress == 3 && (_from == 2 || _from == 4))
	    || (_thisAddress == 4 && _from == 3)
	       // This network looks like 1-2-4
	       //                         | | |
	       //                         --3--
	       (_thisAddress == 1 && (_from == 2 || _from == 3))
	    ||  _thisAddress == 2
	    ||  _thisAddress == 3
	    || (_thisAddress == 4 && (_from == 2 || _from == 3))

	       // This network looks like 1-2-4
	       //                         |   |
	       //                         --3--
	       (_thisAddress == 1 && (_from == 2 || _from == 3))
	    || (_thisAddress == 2 && (_from == 1 || _from == 4))
	    || (_thisAddress == 3 && (_from == 1 || _from == 4))
	    || (_thisAddress == 4 && (_from == 2 || _from == 3))

	       // This network looks like 1-2-3
	       //                           |
	       //                           4
	       (_thisAddress == 1 && _from == 2)
	    ||  _thisAddress == 2
	    || (_thisAddress == 3 && _from == 2)
	    || (_thisAddress == 4 && _from == 2)

#if defined(__AVR)
#define RFM95_CS 8
#define RFM95_RST 7
#define RFM95_INT 2
#define LED 4

RH_RF95 rf95(RFM95_CS, RFM95_INT);

#elif defined(HELTEC_WIFI_LORA_32_V2)

// heltec wifi lora 32 v2
#define RFM95_CS 18
#define RFM95_RST 14
#define RFM95_INT 26
#define LED 25

RH_RF95 rf95(RFM95_CS, RFM95_INT);

#elif defined(FEATHER_ESP32)

// feather esp32
#define RFM95_CS 14
#define RFM95_RST 27
#define RFM95_INT 15
#define LED 13

RHSoftwareSPI sx1278_spi;

RH_RF95 rf95(RFM95_CS, RFM95_INT, sx1278_spi);


2021-02-28 19:46:46



Only the feather m0 and the heltec code works for now I think (easy to make the feather esp32 code work I believe)

NOTE: in order to generate the 'test networks', it has to be done in the RHROUTER.h file in the library itself.

See below, displaying RH_TEST_NETWORK==3:

Documentation on RHMesh here

2021-02-28 20:23:29

Nice LoRa tracker project here

Great thread on using CO2 for indoor ventilation assessment here

2021-03-01 13:55:42

from https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/fatal-errors.html:

LoadProhibited, StoreProhibited This CPU exception happens when application attempts to read from or write to an invalid memory location. The address which was written/read is found in EXCVADDR register in the register dump. If this address is zero, it usually means that application attempted to dereference a NULL pointer. If this address is close to zero, it usually means that application attempted to access member of a structure, but the pointer to the structure was NULL. If this address is something else (garbage value, not in 0x3fxxxxxx - 0x6xxxxxxx range), it likely means that the pointer used to access the data was either not initialized or was corrupted.

Indeed, this is what we're seeing from the stack trace:

initializing node done
RF95 ready
Guru Meditation Error: Core  1 panic'ed (LoadProhibited). Exception was unhandled.
Core 1 register dump:
PC      : 0x400d0dfa  PS      : 0x00060d30  A0      : 0x800d37cc  A1      : 0x3ffb1f60  
A2      : 0x3ffc0214  A3      : 0x00000004  A4      : 0x3ffc0224  A5      : 0x3ffc08b8  
A6      : 0x00000000  A7      : 0x3ffba264  A8      : 0x800d0dee  A9      : 0x3ffb1f40  
A10     : 0x00000000  A11     : 0x00000001  A12     : 0x00000000  A13     : 0x00000003  
A14     : 0x00000001  A15     : 0x00000000  SAR     : 0x0000000e  EXCCAUSE: 0x0000001c  
EXCVADDR: 0x00000001  LBEG    : 0x400eb508  LEND    : 0x400eb525  LCOUNT  : 0x00000000  

Backtrace: 0x400d0dfa:0x3ffb1f60 0x400d37c9:0x3ffb1fb0 0x40088249:0x3ffb1fd0

Is there a way to check whether a pointer is null or not before attempting?

Null pointer material here

Checking for null status in Arduino: https://forum.arduino.cc/index.php?topic=128622.0

Checked for null pointer first, now it works!

Going to implement in other versions, too ...

2021-03-01 14:35:37

Fixed trio! https://github.com/edgecollective/lora-mesh/tree/50f2046267c6fdc4c8f0d68c1d225a53ddbb854c/co2/simple_e

Working basic lora mesh relay code.

Now set up to send CO2 data.

2021-03-01 15:15:49

Mesh healing:

Simple mesh + co2 reading code: https://github.com/edgecollective/lora-mesh/tree/fb1f5d3abc81c1c32d06cecbc9205877d048cef3/co2/simple_f/mesh_featheresp32_hardcoded

Now need to:

the remote nodes should be mostly listening and relaying, then periodically sending their data

the gateway should be mostly listening and relaying the value via wifi whenever something comes in

i guess the only difference is that if the gateway sees that it is the target node then it is never broadcasting, only wifi sending ...

for now we'll http POST every incoming data point, see if that can handle the random lora messages; otherwise we can store N incoming messages, then POST

2021-03-01 15:26:46

testing gateway setup -- adding wifi to gateway node

Feed Public Key: 7zqjzktfq997 Feed Private Key: 4g5xf5xzzhr8 Feed Home Page: http://co2.pvos.org/data/7zqjzktfq997

(on local database)

Ah -- I might want to use 'recvfromAck' (non-blocking) instead of 'recvfromAckTimeout' on the remote nodes.


set up the recvfromAck in the loop (or start it running in setup?)

in remote nodes, periodically send co2 data ...

in the gateway, periodically send the data that has been collected thus far ...

some relevant posts:



example using recvfromAck: https://github.com/adafruit/RadioHead/blob/master/examples/serial/serial_reliable_datagram_server/serial_reliable_datagram_server.pde

2021-03-01 20:45:29

lora-mesh/co2/simple_g/basic_mesh_system/mesh_heltec seems to work as a basic mesh gateway.


will need to test code for other nodes.

need to think through how to handle; seems like each node sends its pubkey, its privkey, and identifies its network by gateway's pubkey.

somehow we have to identify nodes in the network by simple integers, it seems. need to think that through.

note that the gateway should send its own data via http every X seconds ...

... so maybe there's a millis() loop, where if you're the remote node, when it triggers, you send your data via lora; if you're the gateway, you send your data to the cloud via wifi.

the gateway is then set up so that it is listening for chunks of time; if it ever hears anything, it does an http POST of that data; and if it is then also past its own interval, it posts data.

every listen-receive-post re-loops the system

in the limit of many receipts, it simply loops back into another receipt again; but it will always measure itself and send via wifi if it's past time to do so

i.e. something like:

if (millis() > wait interval) {

if we're the gateway, measure our own CO2 and send via wifi;

if we're a remote node, measure our own CO2 and send via lora;


if recvfromAckTimeout(wait interval) { // running this function means that we are relaying any mesh messages // if it returns true, then we were the intended recipient // in our network, this is only true if we're the gateway; so in that case, post the resultant data to the proper feed. }

this means that the data struct has to include the pubkey and privkey of the remote node that is sending the data. the node id would ideally be set in hardware, but we'll do it in the config file in this round. i don't think there's any need to have an upper limit on # nodes; but each nodeid needs to be unique

we should rename nodeId to node_id

2021-03-02 10:41:51

Heating events ...

Exponential decay here

fitting using python here

get slopes of data here

adding fields to bayou:

2021-03-02 18:20:59


  1. adding new column to postgres https://www.postgresqltutorial.com/postgresql-add-column/
ALTER TABLE measurements ADD COLUMN node_id INT;
ALTER TABLE measurements ADD COLUMN next_hop INT;
ALTER TABLE measurements ADD COLUMN next_rssi FLOAT;
ALTER TABLE measurements ADD COLUMN light FLOAT;

need to remember to optimize strings!

need to add lux to database

string args and string cat -- https://forum.arduino.cc/index.php?topic=120233.0

strlcat() -- truncates string if necessary rather than writing outside bounds

2021-03-02 21:31:36

Replaced use of strings with chars; put stuff into functions: https://github.com/edgecollective/lora-mesh/tree/bdec49aedecffb83f29723c3f0fcfdf924c9e2fe/co2/simple_h/mesh_heltec -- basic gateway is working.

Now need to:

2021-03-03 12:43:22

Basic working version for Heltec!


Also includes code for a 'dummy' featherm0 node.

Next priorities:

  1. Change Bayou so that it display the node_id, next_hop, next_rssi
  2. Change Feedmap so that it can display a 'viz' of the network coming through
  3. Make code for a simple relay node in the network

2021-03-03 17:08:56

sorting javascript objects by key https://stackoverflow.com/questions/5467129/sort-javascript-object-by-key

sorting javascript objects by value https://stackoverflow.com/questions/1069666/sorting-object-property-by-values

2021-03-03 17:38:11

working! the "simple_k" arduino version, with associated commits on bayou and feedmap ...

bayou code: https://gitlab.com/p-v-o-s/co2/bayou-co2/-/tree/d738bfcbbd1f4b934a11add33852f7f00267e0fc

feedmap code: https://gitlab.com/p-v-o-s/co2/feedmap/-/tree/52820c9e0cdbdb02808a239cf75fe65ff7360391

arduino firmware: https://github.com/edgecollective/lora-mesh/tree/731e5e392831f657b3cb9bdfb01c6fe3691d9187/co2/simple_k

2021-03-04 09:10:42

Data analysis repo here: https://github.com/p-v-o-s/co2data-analysis/tree/a4879538a447a920785b4d9182a0b38e4830baab/jupyter/heating_mar_04_2020

2021-03-04 13:13:30

Repeaters working!

Arduino firmware is 'simple_l' version: https://github.com/edgecollective/lora-mesh/tree/32dbf22e74e37e31f55ce6855fca599a2c0105f9/co2/simple_l

Feedmap version is in the 'mesh' branch: https://gitlab.com/p-v-o-s/co2/feedmap/-/tree/817f69f4ab2012de69c9be0644be988d19e879e8

Bayou-feed version is https://gitlab.com/p-v-o-s/co2/bayou-co2/-/tree/d738bfcbbd1f4b934a11add33852f7f00267e0fc

2021-03-05 10:15:35

Pandas series to numpy array https://pandas.pydata.org/pandas-docs/version/0.24.0rc1/api/generated/pandas.Series.to_numpy.html

polyfit: https://numpy.org/doc/stable/reference/generated/numpy.polyfit.html




2021-03-06 08:10:48

Error on the fit in numpy: https://stackoverflow.com/questions/15721053/whats-the-error-of-numpy-polyfit

2021-03-07 13:19:18

New mesh code here: https://gitlab.com/p-v-o-s/co2/co2monitor-firmware/-/raw/master/releases/v0.7-alpha.zip

2021-03-10 16:13:42

error in fit: http://clip.med.yale.edu/courses/brdu/Costa_ODE.pdf

error in slope of linear fit: https://pages.mtu.edu/~fmorriso/cm3215/UncertaintySlopeInterceptOfLeastSquaresFit.pdf

SE of regression slope = sb1 = sqrt [ Σ(yi – ŷi)2 / (n – 2) ] / sqrt [ Σ(xi – x)2 ]







2021-03-11 18:17:18

Rework of firmware and bayou for mesh networking ...

Can now use URL parameters to specify node and parameter to graph:

2021-03-12 10:05:53

Added overlay functionality to Bayou:

Still associated with ver 0.8-alpha of firmware:

2021-03-13 08:42:37

New References on CO2 to assess indoor ventilation

Great presentation on using CO2 for assessing ventilation -- recommends using fans: https://www.ghdonline.org/uploads/Measuring_Air_Changes.pdf


International Journal of Ventilation: Simple and Cheap Air Change Rate Measurement Using CO2 Concentration Decays

Medrxiv: Ventilation rate assessment by carbon dioxide levels in dental treatment rooms -- note: uses baking soda! Key paper, here.

Am J Respir Crit Care Med: Measuring ventilation of patient care areas in hospitals. Description of a new protocol

Fitting in JS:






2021-03-13 10:15:09

Updated bayou to find the existing nodes in a feed, and pull JSON and CSV for them:


Still compatible with latest (ver0.8-alpha) software

Some useful folks to add to the list: https://twitter.com/rod_escombe/status/1246117208440418304


2021-03-13 13:08:51

"Natural Ventilation for the Prevention of Airborne Contagion" -- another key paper by Enscombe et al.

2021-03-14 09:00:12

Baking soda and vinegar experiment https://www.thoughtco.com/equation-for-the-reaction-of-baking-soda-and-vinegar-604043

How to make carbon dioxide https://sciencing.com/make-carbon-dioxide-6532065.html

Making CO2 w/ DIY bottle system https://www.co2supermarket.co.uk/diy-co2-kit-setup-instructions-guide-6.html

CO2 in grow rooms, increasing ppm: https://www.rollitup.org/t/co2-generated-via-vinegar-and-baking-soda.397247/

CO2 heavier than air, typically we'll need to use a fan to circulate it in the room


2021-03-14 12:09:47

Showing a fit in chartjs https://stackoverflow.com/questions/42841925/mixed-chart-scatter-plot-with-chart-js

2021-03-14 16:32:35

Select range in chartjs: https://stackoverflow.com/questions/42855738/how-do-i-selecting-a-date-range-like-onclick-but-drag-select

Chartjs plugin zoom: [https://github.com/chartjs/chartjs-plugin-zoom]




2021-03-14 19:44:38

Bayou branch that does curve fitting: https://gitlab.com/p-v-o-s/agroeco/bayou/-/tree/6a97681e2cc36e1e41edc2b6800e00858987fa42

Video demo here

2021-03-16 17:26:51

Added live exponential fit! Bayou commit here: https://gitlab.com/p-v-o-s/agroeco/bayou/-/tree/fe7b5ed71be3ebddf4d0be98c3d1bd88fb758d20

2021-03-17 08:04:41

Nice working prototype of Bayou ACH fit: https://gitlab.com/p-v-o-s/agroeco/bayou/-/tree/1372dc343ec2f9e70449fe0b0628fb26019eac8a


Video here: https://youtu.be/AfVbtuXU_sA

2021-03-17 09:58:58

Brought back in display of linear fit, along with slope and intercept parameters, in the following commit:


2021-03-17 10:11:20

Bayou has format-able canvas size now:


2021-03-17 11:36:09

Nice reference for downloading canvas as a PDF: https://stackoverflow.com/questions/23681325/convert-canvas-to-pdf -- some pretty simple code

2021-03-18 19:00:18

Baking soda exp't #1

Dataset here: http://bayou.pvos.org/data/6adqqks8f7yb/ach/2

In play room -- door closed -- fit one

In play room -- door closed -- fit two

In play room -- door closed -- fit three

... then door open

2021-03-18 19:05:04

Baking soda exp't #2

Dataset here: http://bayou.pvos.org/data/8fs9k3zwjg4w/

2021-03-31 14:51:59

barrel jack connector https://www.sparkfun.com/datasheets/Prototyping/Barrel-Connector-PJ-202A.pdf

pos centerpole on 2.1 mm + USB cable from Amazon ...

extension cable from sparkfun for 2.1 mm jack here

2021-04-17 08:49:02

force calibration event at a2:

![](/img/co2/force_calibration_at _a2.png)


2021-04-17 08:50:02

Current setup idea:

uf2 based board, so we can flash firmware without IDE

microSD card for parameters on gateway; not necessary for remote node, b/c each node can be determined by a switch, and the loranetwork can be set in the firmware -- we can have several options


2021-04-18 10:23:09

uf2 bootloader on feathers2 is not protected. this means that arduino ide upload will likely erase UF2 (way to mitigate this?) and in fact does in my experience.

But 'advanced' users who use Arduino IDE w/ esp32 setup should also likely be able to handle webserial or other modes of re-flashing the bootloader.


tempting to use the itsy bitsy, but sticking with the feather ecosystem if possible seems smart.

esp32-s2 feathers2 as main board seems like a good setup if we can swing it. means that gateway and remote node are identical setups.

making uf2s --- https://github.com/blurfl/makeUF2-tool

python /home/dwblair/.arduino15/packages/esp32/tools/esptool_py/3.0.0/esptool.py --chip esp32s2 --port /dev/ttyACM0 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size detect 0xe000 /home/dwblair/.arduino15/packages/esp32/hardware/esp32/2.0.0-alpha1/tools/partitions/boot_app0.bin 0x1000 /tmp/arduino_build_224941/Blink_S2.ino.bootloader.bin 0x10000 /tmp/arduino_build_224941/Blink_S2.ino.bin 0x8000 /tmp/arduino_build_224941/Blink_S2.ino.partitions.bin 

important video to watch: https://www.youtube.com/watch?v=xmB22q2p40g

instructions for loading the uf2 bootloader https://feathers2.io/install_uf2.html

esptool.py --chip esp32s2 -p /dev/cu.usbmodem01 -b 921600 --before=default_reset --after=no_reset write_flash --flash_mode dio --flash_size detect --flash_freq 80m 0x1000 bootloader.bin 0x8000 partition-table.bin 0xe000 ota_data_initial.bin 0x410000 tinyuf2.bin

options for setting up system:


option A:

option b:


option A:

----> this is the major thing to test right now

option B:

samd51 in standby mode -- can use sleepdog library -- https://forum.arduino.cc/t/samd51-sleep-mode/591685 -- get 43 uA

2021-04-18 15:14:29





2021-04-18 16:14:31

core code for project! M0 + uSD + lora + esp32 wifi breakout (tested on itsybitsy)


2021-04-18 19:14:53

mini ultra -- https://www.rocketscream.com/blog/product/mini-ultra/

mini ultra pro https://github.com/rocketscream/MiniUltraPro

samd51 easier part ot solder https://www.digikey.com/en/products/detail/microchip-technology/ATSAMD51N20A-AUT/7390290

https://twitter.com/marwa_zaatari/status/1383828012022439937?s=20 good thread on hvac

2021-04-20 13:22:50

adding adalogger to feather m0 lora: https://forums.adafruit.com/viewtopic.php?f=31&p=856795

This thread indicates that the original Arduino SD library shouldn't be used with more than one device on the SPI bus; use SdFAT instead https://forum.arduino.cc/t/problem-using-both-spi-library-and-sd-library-in-arduino-uno-program/149775/16, and making sure to set the relevant pins high or low depending on which device you want to talk to

2021-04-24 11:26:44

Ordered CO2 REV_K / REV K from JLCPCB -- git commit is here: https://gitlab.com/p-v-o-s/co2/co2monitor-hardware/-/tree/2f2a087edde58be6938c8b4bdc3f76482e28a35f/REV_K/kicad

2021-04-24 11:37:42

Gateway design:

set up 'all breakout' option, so that the basic soldering req'd is:

going to work on this using 'gateway' file in co2monitor-firmware v0.91-alpha

NOTE: if someone were to use a feather m0 lora, they'd have to load firmware via arduino ide anyway ... so virtual lora connection is fine.

Need to see if hardware uSD and hardware airlift are compatible ...

But: looks like uSD doesn't 'play nice' with other SPI devices. so: let's see if we can do hardware lora and hardware airlift; then virtual uSD.

2021-04-24 12:22:18

feather m0 express + hardware airlift and hardware lora working in this commit: https://gitlab.com/p-v-o-s/co2/co2monitor-firmware/-/tree/b21eeb06612cf2d21b35c77848c71bd4566b9cc5/v0.91-alpha/gateway/featherm0express_hardware_airlift_ScanNetworks_hardware_lora

virtual SPi on m0 reference here: https://learn.adafruit.com/using-atsamd21-sercom-to-add-more-spi-i2c-serial-ports?gclid=CjwKCAjwg4-EBhBwEiwAzYAlsoaFHbvfOeNx0AQbUp4pAbEmXst8Mpb2HCE15YLEejIkYbjp9jlnWRoC4VkQAvD_BwE


challenging to create virtual SPI for uSD ... ? can't find in library as yet ...

another option might be to do virtual SPI for lora + airlift ...

quick test of that ...

2021-04-24 14:32:12

basic test of: featherm0express + hardware_airlift + hardware uSD + virtual LoRa here: https://gitlab.com/p-v-o-s/co2/co2monitor-firmware/-/tree/a0e75274df4518dbe081546bc32aacd0a79d6e80/v0.91-alpha/gateway/featherm0express_airlift_test_hardware_uSD_virtual_LoRa

now try writing to uSD, connecting to wifi, and sending lora packet in loop ...

2021-04-24 14:43:32

note: seems like airlift (which includes 3.3V LDO) can do alright on 3.7 lithium ion battery (gets sufficient current)

2021-04-24 15:21:12

was able to read config file and then use wifi -- also lora -- now need to write gateway firmware to test! -- commit is here: https://gitlab.com/p-v-o-s/co2/co2monitor-firmware/-/tree/d7d8ad2ac631a02f62a4df86c8642994a86d8005/v0.91-alpha/gateway/featherm0express_airlift_test_hardware_uSD_virtual_LoRa_readcon

2021-04-26 17:34:57

2021-04-29 11:22:02

design updates:

base around itsy bitsy m0 / m4 diy version can be hand soldered easily microsd breakout option battery power is: cell battery module force calibrate procedure

then next version: cheaper, SMT

samd51 deep sleep mode: https://forum.arduino.cc/t/standby-sleep-mode-on-samd51/576584/4

note: we don't really need to worry about the samd51 sleeping -- we'll probably only use it when doing circuitpython, on the gateway, if we want to do that ... but the gateway usually won't be sleeping ... at least not for many applications ...

2021-04-30 10:20:04

IBM4 + uSD (hardware SPI) + esp32 airlift featherwing (hardware SPI) + LoRa (virtual SPI): https://gitlab.com/p-v-o-s/co2/co2monitor-firmware/-/tree/95aca8ffeebd98583e0790de480f285ef62d94da/v0.91-alpha/ibm4_hardware_airliftwing_hardware_uSD_virtual_LoRa

above, + OLED + SCD30: https://gitlab.com/p-v-o-s/co2/co2monitor-firmware/-/tree/59575acfdf487dab619edb50be38fe54dbf7a503/v0.91-alpha/ibm4_hard_airliftwing_hard_uSD_soft_LoRa_i2c_oled_i2c_scd30

note: looks like we have another reason for using the IBM4 -- we need the extra pins?

pinouts for esp32 airlift featherwing -- https://learn.adafruit.com/adafruit-airlift-featherwing-esp32-wifi-co-processor-featherwing/pinouts

upgrading firmware https://learn.adafruit.com/adafruit-airlift-featherwing-esp32-wifi-co-processor-featherwing/upgrade-external-esp32-airlift-firmware

okay -- need a pint on GPIO0 ---

Rotary coded switch


Part from digikey here: https://www.digikey.com/en/products/detail/nidec-copal-electronics/SD-2010/948380

Datasheet: https://www.nidec-copal-electronics.com/e/catalog/switch/sd-1000&sd-2000.pdf

2021-05-01 12:19:15


2021-05-01 13:43:06

maxim unique id chip https://www.digikey.com/en/products/detail/maxim-integrated/DS2401/956992


So the probability of no collisions is exp(-1/2) or about 60%, which means there’s a 40% chance of at least one collision. As a rule of thumb, a hash function with range of size N can hash on the order of √N values before running into collisions.



2021-05-01 14:46:31

using spi flash on feather m0 express: https://learn.adafruit.com/adafruit-feather-m0-express-designed-for-circuit-python-circuitpython/using-spi-flash

2021-05-01 17:28:23

airlift featherwing esp32 schematic https://cdn-learn.adafruit.com/assets/assets/000/076/198/original/adafruit_products_AirLift_FeatherWing_Sch.png?1559155254

best practices for neopixels https://learn.adafruit.com/adafruit-neopixel-uberguide/best-practices

2021-05-01 17:45:25

2021-05-01 17:52:23

esp32 wroom antenna placement options https://www.espressif.com/sites/default/files/documentation/esp-wroom-02_pcb_design_and_module_placement_guide_0.pdf

2021-05-01 18:19:20

esp32 add-on for itsy bitsy schematic: https://cdn-learn.adafruit.com/assets/assets/000/080/457/original/adafruit_products_schematic.png?1567623352

ibm4 EXPRESS https://cdn-learn.adafruit.com/assets/assets/000/055/481/original/adafruit_products_schem.png?1529261754

DS2401 -- maxim through-hole serial # chip: https://www.digikey.com/en/products/detail/maxim-integrated/DS2401/956992

maxim additional chip: https://www.digikey.com/en/products/detail/maxim-integrated/DS28CM00R-A00-T/1197555

2021-05-01 19:03:10

incorporated latest changes to REV_L here: https://gitlab.com/p-v-o-s/co2/co2monitor-hardware/-/tree/064aa5c7a90d85fe930543ed271bc1fce1ff6d45/REV_L/kicad

2021-05-02 10:24:28

Board files on github: https://github.com/adafruit/NeoPixel-Sticks

2021-05-02 19:12:47

Latest REV_K is here: https://gitlab.com/p-v-o-s/co2/co2monitor-hardware/-/commit/acc99be30c98ecd960c28571723e39a166e170a5

2021-05-05 11:26:02


motor for dump truck:


linear actuator from scratch https://www.hackster.io/news/a-linear-actuator-made-from-scratch-b89c3c389003

2021-05-05 14:32:02

itsy bitsy m4 pinout:

interesting ref on partitioning esp32 here: https://towardsdatascience.com/tensorflow-meet-the-esp32-3ac36d7f32c7

2021-06-26 08:10:10

Working on REV_L with Mike, Craig, and Brett ...

Indoor ACH experiment w/ CO2 (in Spanish)

Working on getting the ACH fitting working again on Bayou ...

Craig's feed / setup

Craig's bayou feed: http://bayou.pvos.org/data/sj5ppfn94meh

Mike's feed / setup

Mike's bayou feed: http://bayou.pvos.org/data/kurqr92abvua

2021-06-26 09:46:48

Video explaining current interface for assessing ACH using Bayou: https://youtu.be/xXAM4NldULA


2021-06-26 13:03:46

Mike's 'box test':

Quick video showing ACH analysis for node #2: https://youtu.be/7Rr_agMS50k

2021-07-22 21:15:55

REV_L Response Test
ENCLOSURE ON: A. Force calibrated outdoors; then transported sensor indoors into small room; B. CO2 injection into room; C. Transport of sensor outdoors (< 10 seconds transport duration); D. Return sensor to small room (which still has high CO2 concentration). E. Remove enclosure. ENCLOSURE OFF: F. Transport sensor outdoors (< 10 seconds transport time).

2021-07-23 10:58:04

Design-in guidelines for SCD30

Seems to argue for larger ventilation holes, smaller inside enclosure.

Might just place holes directly beneath the sensor.

2021-07-25 11:29:17

Enclosure experiments

Option A

Sensor inside enclosure, sensor close to 'pcb'; square hole cut out as per build-in guidelines; no tape around sensor.

Ambient CO2 level; brought from inside out to outside in < 5 seconds. Same outside to inside, but ambient CO2 indoors may have been lower; then people entered room.

Option B

No enclosure; sensor close to 'pcb'; no tape around board.

Comparison of option A and option B:

Note that when we'd calibrated using the 'slow' enclosure, it looks as though we didn't actually give the sensor enough time to reach ambient; when the enclosure is removed, we dropped down to ambient.

Option C

No enclosure; sensor close to 'pcb', tape around sensor to create 'small enclosure'

(graphic shows events for options a, b, c from left to right)

Option D

Enclosure; sensor close to 'pcb', tape around sensor to create 'small enclosure'.

Note that there are CO2 intakes on top and bottom of sensor. The top of the sensor is not taped. The below behavior in fact indicates that by having the bottom exposed only to the outside, and the top exposed only to the outside, we are somewhat 'averaging' the measurement (with a slow leak).

(graphic shows events for options a,b,c,d from left to right)

Option E

Enclosure; sensor close to 'pcb', tape around sensor to create 'small enclosure'; also covered 'top' of sensor to avoid intake on top.

Note that what appears to be happening is that I've sealed in a slightly higher CO2 env on the top, by putting tape on top of the intakes. Also, the sensor responds a bit slower with only the bottom intakes (perhaps the time constant is 'half' as fast as with top and bottom intakes exposed?).

So: as per Mike's suggestion, let's create the tightest enclosure around the sensor that also allows air to flow up over the intakes ...

(Note: I think spike on far right is me exhaling towards sensor accidentally while writing these notes ...)

(graphic shows events for options b,c,d from left to right; option a is only partially visible on left)

Option F

Made a "small box" that has some finite volume but still allows air flow over the top part of the sensor.

Note that the ends of the response (drop down and rise up) seem a bit more rounded / slower ... perhaps because of the small reservoir of gas inside the enclosure ...

(options a,b,c,d,e,f from left to right below:)


Looks like the sensor is about 9 or 10 mm peak off board, with sides around 5 mm; the intakes on the 'top' would still have some breathing room if tape was put over the top; so 8.5 mm headers could work pretty well as 'sides'

2021-07-25 16:51:24

Bug via Dave S.

2021-07-27 19:56:53

Summary of PCB ventilation experiment ...

2021-07-28 19:52:05

Final report TU Delft comparing CO2 sensor technologies: https://repository.tudelft.nl/islandora/object/uuid:6957a1c1-6ece-41b9-9802-2674c9365339/datastream/OBJ/download

Crodeon deployment of SCD30 https://www.crodeon.com/products/covid-co2-kit

2021-07-28 19:56:28

SCD40 https://www.semiconductorstore.com/blog/2021/SCD4x-CO2-Sensor-Frequently-Asked-Questions-Symmetry-Blog/4380/

SCD40 design-in guidelines https://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/9.5_CO2/Sensirion_CO2_Sensors_SCD4x_design-in_guide.pdf

2021-08-08 20:57:45

Notes on Corsi interview:

don't ever get worse results, but might be waste of time ...

keep devices 3ft away from walls / out of corners -- to avoid recirculation

don't want to put e.g. in front of window

look at classroom -- where is air coming in, where is air flowing out -- don't put device close to where air is flowing out

in general -- would try to put two boxes diagonally apart in the classroom

next to each other -- 'short circuiting'

600 700 800 900

sucks in through filters and out through fan

air blow vertically upward -- good -- want circulating flow up and diagonally across

weird fluid flow phenomena -- suck air in corners at filter

pleated merv 13 means greater surface area, less resistance, lower average velocity, reduces resistance on fan

filters as designed are capturing particles on surface of filter -- there's no barrier -- so:

CO2 Monitor notes:

Airboxes are imporant when you can't get better ventilation -- i.e. poor mechanical systems or

36:00 -- The true metric using CO2 is the 'rebreathe fraction' -- how much you're breating other people's breath. If you have a rebreathe fraction of 5% -- really high, bad. Rebreathe fraction of .5% is much better. Rebreathe fraction is: (CO2 concentration in room - CO2 concentration outdoors) / CO2 concentration on typical human breath -- also a function of who is the space -- dynamics are important ...

Building boxes lowers aerosol particle levels in the classroom

2021-08-19 12:54:18

co2 monitor --

feather m4 express, because:

esp32 airlift, because:

add a buzzer

2021-09-07 13:28:29

CO2 sensors useful in schools generally