diff --git a/Trinkey_QT2040_Enviro_Gadget/arduino/.test.only.qt2040_trinkey b/Trinkey_QT2040_Enviro_Gadget/arduino/.test.only.qt2040_trinkey new file mode 100644 index 000000000..e69de29bb diff --git a/Trinkey_QT2040_Enviro_Gadget/arduino/trinkey_qt2040_enviro/trinkey_qt2040_enviro.ino b/Trinkey_QT2040_Enviro_Gadget/arduino/trinkey_qt2040_enviro/trinkey_qt2040_enviro.ino new file mode 100755 index 000000000..4ea2ab447 --- /dev/null +++ b/Trinkey_QT2040_Enviro_Gadget/arduino/trinkey_qt2040_enviro/trinkey_qt2040_enviro.ino @@ -0,0 +1,111 @@ +// SPDX-FileCopyrightText: 2021 Carter Nelson for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include +#include +#include +#include + +//--| User Config |----------------------------------------------- +#define DATA_FORMAT 0 // 0=CSV, 1=JSON +#define DATA_RATE 5000 // generate new number ever X ms +#define BEAT_COLOR 0xADAF00 // neopixel heart beat color +#define BEAT_RATE 1000 // neopixel heart beat rate in ms, 0=none +//---------------------------------------------------------------- + +Adafruit_BME280 bme; +SensirionI2CScd4x scd4x; +Adafruit_NeoPixel neopixel(1, PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800); + +uint16_t CO2, data_ready; +float scd4x_temp, scd4x_humid; +float temperature, humidity, pressure; +int current_time, last_data, last_beat; + +void setup() { + Serial.begin(115200); + + // init status neopixel + neopixel.begin(); + neopixel.fill(0); + neopixel.show(); + + // init BME280 first, this calls Wire.begin() + if (!bme.begin()) { + Serial.println("Failed to initialize BME280."); + neoPanic(); + } + + // init SCD40 + scd4x.begin(Wire); + scd4x.stopPeriodicMeasurement(); + if (scd4x.startPeriodicMeasurement()) { + Serial.println("Failed to start SCD40."); + neoPanic(); + } + + // init time tracking + last_data = last_beat = millis(); +} + +void loop() { + current_time = millis(); + + //----------- + // Send Data + //----------- + if (current_time - last_data > DATA_RATE) { + temperature = bme.readTemperature(); + pressure = bme.readPressure() / 100; + humidity = bme.readHumidity(); + scd4x.setAmbientPressure(uint16_t(pressure)); + scd4x.readMeasurement(CO2, scd4x_temp, scd4x_humid); + switch (DATA_FORMAT) { + case 0: + sendCSV(); break; + case 1: + sendJSON(); break; + default: + Serial.print("Unknown data format: "); Serial.println(DATA_FORMAT); + neoPanic(); + } + last_data = current_time; + } + + //------------ + // Heart Beat + //------------ + if ((BEAT_RATE) && (current_time - last_beat > BEAT_RATE)) { + if (neopixel.getPixelColor(0)) { + neopixel.fill(0); + } else { + neopixel.fill(BEAT_COLOR); + } + neopixel.show(); + last_beat = current_time; + } +} + +void sendCSV() { + Serial.print(CO2); Serial.print(", "); + Serial.print(pressure); Serial.print(", "); + Serial.print(temperature); Serial.print(", "); + Serial.println(humidity); +} + +void sendJSON() { + Serial.print("{"); + Serial.print("\"CO2\" : "); Serial.print(CO2); Serial.print(", "); + Serial.print("\"pressure\" : "); Serial.print(pressure); Serial.print(", "); + Serial.print("\"temperature\" : "); Serial.print(temperature); Serial.print(", "); + Serial.print("\"humidity\" : "); Serial.print(humidity); + Serial.println("}"); +} + +void neoPanic() { + while (1) { + neopixel.fill(0xFF0000); neopixel.show(); delay(100); + neopixel.fill(0x000000); neopixel.show(); delay(100); + } +} diff --git a/Trinkey_QT2040_Enviro_Gadget/circuitpython/boot.py b/Trinkey_QT2040_Enviro_Gadget/circuitpython/boot.py new file mode 100755 index 000000000..46671ec2f --- /dev/null +++ b/Trinkey_QT2040_Enviro_Gadget/circuitpython/boot.py @@ -0,0 +1,2 @@ +import usb_cdc +usb_cdc.enable(data=True) \ No newline at end of file diff --git a/Trinkey_QT2040_Enviro_Gadget/circuitpython/enviromon.py b/Trinkey_QT2040_Enviro_Gadget/circuitpython/enviromon.py new file mode 100755 index 000000000..95f1f956a --- /dev/null +++ b/Trinkey_QT2040_Enviro_Gadget/circuitpython/enviromon.py @@ -0,0 +1,69 @@ +# SPDX-FileCopyrightText: 2021 Carter Nelson for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +import time +import board +import usb_cdc +import adafruit_scd4x +from adafruit_bme280 import basic as adafruit_bme280 +import neopixel + +#--| User Config |----------------------------------- +DATA_FORMAT = "JSON" # data format, CSV or JSON +DATA_RATE = 5 # data read rate in secs +BEAT_COLOR = 0xADAF00 # neopixel heart beat color +BEAT_RATE = 1 # neopixel heart beat rate in secs, 0=none +#---------------------------------------------------- + +# check that USB CDC data has been enabled +if usb_cdc.data is None: + print("Need to enable USB CDC serial data in boot.py.") + while True: + pass + +# setup stuff +scd = adafruit_scd4x.SCD4X(board.I2C()) +scd.start_periodic_measurement() +bme = adafruit_bme280.Adafruit_BME280_I2C(board.I2C()) +pixel = neopixel.NeoPixel(board.NEOPIXEL, 1) + +# CSV output +def send_csv_data(data): + usb_cdc.data.write("{}, {}, {}, {}\n".format(*data).encode()) + +# JSON output +def send_json_data(data): + usb_cdc.data.write('{'.encode()) + usb_cdc.data.write('"CO2" : {},'.format(data[0]).encode()) + usb_cdc.data.write('"pressure" : {},'.format(data[1]).encode()) + usb_cdc.data.write('"temperature" : {},'.format(data[2]).encode()) + usb_cdc.data.write('"humidity" : {}'.format(data[3]).encode()) + usb_cdc.data.write('}\n'.encode()) + +# init time tracking +last_data = last_beat = time.monotonic() + +# loop forever! +while True: + current_time = time.monotonic() + + # data + if current_time - last_data > DATA_RATE: + data = (scd.CO2, bme.pressure, bme.temperature, bme.humidity) + usb_cdc.data.reset_output_buffer() + if DATA_FORMAT == "CSV": + send_csv_data(data) + elif DATA_FORMAT == "JSON": + send_json_data(data) + else: + usb_cdc.data.write(b"Unknown data format.\n") + last_data = current_time + + # heart beat + if BEAT_RATE and current_time - last_beat > BEAT_RATE: + if (pixel[0][0]): + pixel.fill(0) + else: + pixel.fill(BEAT_COLOR) + last_beat = current_time diff --git a/Trinkey_QT2040_Enviro_Gadget/python/read_csv.py b/Trinkey_QT2040_Enviro_Gadget/python/read_csv.py new file mode 100755 index 000000000..9056d6937 --- /dev/null +++ b/Trinkey_QT2040_Enviro_Gadget/python/read_csv.py @@ -0,0 +1,21 @@ +# SPDX-FileCopyrightText: 2021 Carter Nelson for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +import serial + +# open serial port (NOTE: change location as needed) +ss = serial.Serial("/dev/ttyACM0") + +# read string +_ = ss.readline() # first read may be incomplete, just toss it +raw_string = ss.readline().strip().decode() + +# create list of floats +data = [float(x) for x in raw_string.split(',')] + +# print them +print("CO2 =", data[0]) +print("pressure =", data[1]) +print("temperature =", data[2]) +print("humidity =", data[3]) \ No newline at end of file diff --git a/Trinkey_QT2040_Enviro_Gadget/python/read_json.py b/Trinkey_QT2040_Enviro_Gadget/python/read_json.py new file mode 100755 index 000000000..5dba166be --- /dev/null +++ b/Trinkey_QT2040_Enviro_Gadget/python/read_json.py @@ -0,0 +1,22 @@ +# SPDX-FileCopyrightText: 2021 Carter Nelson for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +import json +import serial + +# open serial port (NOTE: change location as needed) +ss = serial.Serial("/dev/ttyACM0") + +# read string +_ = ss.readline() # first read may be incomplete, just toss it +raw_string = ss.readline().strip().decode() + +# load JSON +data = json.loads(raw_string) + +# print data +print("CO2 =", data['CO2']) +print("pressure =", data['pressure']) +print("temperature =", data['temperature']) +print("humidity =", data['humidity']) \ No newline at end of file diff --git a/Trinkey_QT2040_Enviro_Gadget/u2if/enviro_u2if.py b/Trinkey_QT2040_Enviro_Gadget/u2if/enviro_u2if.py new file mode 100755 index 000000000..cb186a302 --- /dev/null +++ b/Trinkey_QT2040_Enviro_Gadget/u2if/enviro_u2if.py @@ -0,0 +1,20 @@ +# SPDX-FileCopyrightText: 2021 Carter Nelson for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +import time +import board +import adafruit_scd4x +from adafruit_bme280 import basic as adafruit_bme280 + +scd = adafruit_scd4x.SCD4X(board.I2C()) +scd.start_periodic_measurement() + +bme = adafruit_bme280.Adafruit_BME280_I2C(board.I2C()) + +while True: + time.sleep(5) + print("CO2 =", scd.CO2) + print("Pressure = {:.1f} hPa".format(bme.pressure)) + print("Temperature = {:.1f} degC".format(bme.temperature)) + print("Humidity = {:.1f}%".format(bme.humidity))