Compare commits

...

28 Commits

Author SHA1 Message Date
Ollo
02a5095bf6 keep the RGB status, during sleeping 2021-12-23 15:29:49 +01:00
Ollo
210222799a Prepared sleeping 2021-12-23 14:34:47 +01:00
Ollo
c93c76ab52 Manual merge from standalone; Added mMeasureIndex 2021-12-23 14:00:18 +01:00
Ollo
33ef6bc21b Do not publish invalid PM2.5 values 2021-12-21 13:18:46 +01:00
Ollo
c0aa9c8da1 Reduce cycle time 2021-12-15 20:21:14 +01:00
Ollo
21ba43bbf9 twice the same define... deleted second one 2021-12-15 20:18:22 +01:00
Ollo
d6e34a8e75 Brightness can be configured 2021-12-15 17:22:10 +01:00
Ollo
db10de101c Reduced brightness to 50% 2021-12-15 17:02:36 +01:00
Ollo
dadee863b8 GPIO and Arduino-Pins are never the same 2021-12-12 17:45:45 +01:00
Ollo
5ece74b0e6 Activate I2C after powering the sensor 2021-12-12 17:07:20 +01:00
Ollo
6af6a6ac76 Use red led to visualize button presses 2021-12-12 16:47:40 +01:00
Ollo
e3fe70dff2 Removed unnecessary DEFINE 2021-12-12 16:28:53 +01:00
Ollo
fd8277b702 Don't manipulate the green LED during runtime, as it is the powersource for the I2C sensor 2021-12-12 16:00:45 +01:00
Ollo
3e89b3e040 Tweak offset 2021-12-12 14:48:26 +01:00
Ollo
e52300b792 Update Button via MQTT 2021-12-12 14:45:34 +01:00
Ollo
f3d439cbc3 Button is published on MQTT, too 2021-12-12 14:32:29 +01:00
Ollo
1c35094cfa Wait until power is stable for BME680 2021-12-06 20:28:34 +01:00
Ollo
b2db51d9a9 Spelling improved 2021-12-06 20:18:23 +01:00
Ollo
1cf8c781eb used most commented version 2021-12-06 20:14:55 +01:00
Ollo
c39ebc8e54 Serial debugging enabled 2021-12-04 23:24:30 +01:00
Ollo
1e15d85d6f Set LED to RED, if no configuration is available 2021-12-04 23:09:54 +01:00
Ollo
afff1275da Documentation 2021-12-04 23:09:07 +01:00
Ollo
d910d0b945 More documentation 2021-12-04 18:46:17 +01:00
Ollo
49312a203d Spelling 2021-11-27 15:22:05 +01:00
Ollo
7567a4ef07 Automatic mode is set; instead of ON 2021-11-27 14:56:19 +01:00
Ollo
595fbbc3da Continue with BME680 2021-11-27 12:32:03 +01:00
Ollo
8e24c171ec Spelling corrected 2021-11-27 12:30:39 +01:00
Ollo
9807aa9818 BME680 and BMP280 code merged 2021-11-27 12:29:27 +01:00
6 changed files with 252 additions and 92 deletions

View File

@ -3,7 +3,7 @@ located in IKEAs Vindriktning
after this upgrade it will measure: after this upgrade it will measure:
* air quality * air quality
* temperatur * temperature
* pressure * pressure
* altitude * altitude
@ -39,10 +39,10 @@ VCC | GND
``` ```
The following pins are used: The following pins are used:
* GPIO4 PM1006 particle sensor * GPIO4 PM1006 particle sensor PIN REST on Vindriktning board
* GPIO2 WS2812 stripe out of three LEDs, replacing the orignal LEDs at front * GPIO2 WS2812 stripe out of three LEDs, replacing the original LEDs at front
* GPIO15 Red LED (optional) * GPIO15 Red LED (optional)
* GPIO12 Green LED (optional) * GPIO12 Green LED (optional) Used as 3.3V Supply for the I2C sensor
* GPIO13 Blue LED (optional) * GPIO13 Blue LED (optional)
* GPIO13 VCC of I2C (3.3 V) * GPIO13 VCC of I2C (3.3 V)
* GPIO14 I2C clock * GPIO14 I2C clock
@ -55,4 +55,6 @@ The following pins are used:
* some wire * some wire
# Sources # Sources
* [https://github.com/amkuipers/witty Witty pinout] For the Witty board
* [https://github.com/amkuipers/witty Witty pinout]
* [https://arduino.ua/products_pictures/large_AOC361-5.jpg Schematics]

View File

@ -27,7 +27,7 @@ usage: ota_updater.py [-h] -l BROKER_HOST -p BROKER_PORT [-u BROKER_USERNAME]
[-d BROKER_PASSWORD] [-t BASE_TOPIC] -i DEVICE_ID [-d BROKER_PASSWORD] [-t BASE_TOPIC] -i DEVICE_ID
firmware firmware
ota firmware update scirpt for ESP8226 implemenation of the Homie mqtt IoT ota firmware update script for ESP8226 implementation of the Homie mqtt IoT
convention. convention.
positional arguments: positional arguments:

View File

@ -7,5 +7,6 @@ if [ $? -ne 0 ]; then
fi fi
codespell -w ../src/* codespell -w ../src/*
codespell -w ../include/* codespell -w ../include/*
codespell ../Readme.md codespell -w ../*.md
codespell -w *.md
exit 0 exit 0

View File

@ -12,7 +12,7 @@
#ifndef HOMIE_SETTINGS #ifndef HOMIE_SETTINGS
#define HOMIE_SETTINGS #define HOMIE_SETTINGS
#define HOMIE_FIRMWARE_NAME "Vindriktning" #define HOMIE_FIRMWARE_NAME "RoomSensor"
#define HOMIE_FIRMWARE_VERSION "1.2.1" #define HOMIE_FIRMWARE_VERSION "2.3.0"
#endif #endif

View File

@ -12,11 +12,17 @@
platform = espressif8266 platform = espressif8266
board = d1_mini board = d1_mini
framework = arduino framework = arduino
build_flags = -D PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY build_flags = -D PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY -D BME680
; build_flag needs define the Bosch sensor...
; -D BMP280
;or
; -D BME680
; the latest development branch (convention V3.0.x) ; the latest development branch (convention V3.0.x)
lib_deps = https://github.com/homieiot/homie-esp8266.git#develop lib_deps = https://github.com/homieiot/homie-esp8266.git#develop
EspSoftwareSerial EspSoftwareSerial
NeoPixel NeoPixel
adafruit/Adafruit BMP280 Library @ ^2.4.2
adafruit/Adafruit BME680 Library @ ^2.0.1 adafruit/Adafruit BME680 Library @ ^2.0.1
upload_port = /dev/ttyUSB1 upload_port = /dev/ttyUSB0

View File

@ -18,30 +18,42 @@
#include <Adafruit_NeoPixel.h> #include <Adafruit_NeoPixel.h>
#include <Wire.h> #include <Wire.h>
#include <Adafruit_Sensor.h> #include <Adafruit_Sensor.h>
#ifdef BME680
#include "Adafruit_BME680.h" #include "Adafruit_BME680.h"
#else
#ifdef BMP280
#include "Adafruit_BMP280.h"
#else
#error "Decition, which BMx??? is used missing"
#endif
#endif
/****************************************************************************** /******************************************************************************
* DEFINES * DEFINES
******************************************************************************/ ******************************************************************************/
#define GPIO_WS2812 D4 /**< GPIO2 */ #define GPIO_WS2812 D4 /**< GPIO2 */
#define SENSOR_PM1006_RX D2 /**< GPIO4 */ #define SENSOR_PM1006_RX D2 /**< GPIO4 */
#define SENSOR_PM1006_TX -1 /**< Unused */ #define SENSOR_PM1006_TX -1 /**< Unused */
#define WITTY_RGB_R D8 /**< GPIO15 */ #define WITTY_RGB_R D8 /**< GPIO15 */
#define WITTY_RGB_G D6 /**< GPIO12 */ #define WITTY_RGB_G D6 /**< GPIO12 Used as 3.3V Power supply for the I2C Sensor */
#define WITTY_RGB_B D7 /**< GPIO13 */ #define WITTY_RGB_B D7 /**< GPIO13 */
#define PM1006_BIT_RATE 9600 #define PM1006_BIT_RATE 9600
#define PM1006_MQTT_UPDATE 5000 /**< Check the sensor every 10 seconds; New measurement is done every 20seconds by the sensor */ #define PM1006_MQTT_UPDATE 30000 /**< Check the sensor every 30 seconds; New measurement is done every 20seconds by the PM1006 sensor */
#define PIXEL_COUNT 3 #define PIXEL_COUNT 3
#define GPIO_BUTTON SENSOR_PM1006_RX /**< Button and software serial share one pin on Witty board */ #define GPIO_BUTTON SENSOR_PM1006_RX /**< Button and software serial share one pin on Witty board */
#define SENSOR_I2C_SCK D1 /**< GPIO14 - I2C clock pin */ #define SENSOR_I2C_SCK D5 /**< GPIO14 - I2C clock pin */
#define SENSOR_I2C_SDI D5 /**< GPIO5 - I2C data pin */ #define SENSOR_I2C_SDI D1 /**< GPIO5 - I2C data pin */
#define PM1006_BIT_RATE 9600
#define PM1006_MQTT_UPDATE 5000 /**< Check the sensor every 10 seconds; New measurement is done every 20seconds by the sensor */
#define SEALEVELPRESSURE_HPA (1013.25) #define SEALEVELPRESSURE_HPA (1013.25)
#define BUTTON_MAX_CYCLE 10000U /**< Action: Reset configuration */
#define BUTTON_MIN_ACTION_CYCLE 55U /**< Minimum cycle to react on the button (e.g. 5 second) */
#define BUTTON_CHECK_INTERVALL 100U /**< Check every 100 ms the button state */
#define MIN_MEASURED_CYCLES 2
#define PM_MAX 1001 /**< According datasheet https://en.gassensor.com.cn/ParticulateMatterSensor/info_itemid_105.html 1000 is the maximum */
#define LOG_TOPIC "log\0" #define LOG_TOPIC "log\0"
#define MQTT_LEVEL_ERROR 1 #define MQTT_LEVEL_ERROR 1
#define MQTT_LEVEL_WARNING 10 #define MQTT_LEVEL_WARNING 10
@ -62,6 +74,8 @@
strcat(topic, "/"); \ strcat(topic, "/"); \
strcat(topic, test); strcat(topic, test);
#define PERCENT2FACTOR(b, a) ((b * a.get()) / 100)
#define NUMBER_TYPE "Number" #define NUMBER_TYPE "Number"
#define NODE_PARTICLE "particle" #define NODE_PARTICLE "particle"
#define NODE_TEMPERATUR "temp" #define NODE_TEMPERATUR "temp"
@ -70,6 +84,8 @@
#define NODE_GAS "gas" #define NODE_GAS "gas"
#define NODE_HUMIDITY "humidity" #define NODE_HUMIDITY "humidity"
#define NODE_AMBIENT "ambient" #define NODE_AMBIENT "ambient"
#define NODE_BUTTON "button"
#define SERIAL_RCEVBUF_MAX 80 /**< Maximum 80 characters can be received from the PM1006 sensor */
/****************************************************************************** /******************************************************************************
* TYPE DEFS * TYPE DEFS
******************************************************************************/ ******************************************************************************/
@ -86,36 +102,62 @@ void log(int level, String message, int code);
bool mConfigured = false; bool mConfigured = false;
bool mConnected = false; bool mConnected = false;
bool mOTAactive = false; /**< Stop sleeping, if OTA is running */
bool mFailedI2Cinitialization = false; bool mFailedI2Cinitialization = false;
long mLastButtonAction = 0;
/******************************* Sensor data **************************/ /******************************* Sensor data **************************/
HomieNode particle(NODE_PARTICLE, "particle", "number"); /**< Measuret in micro gram per quibik meter air volume */ HomieNode particle(NODE_PARTICLE, "particle", "number"); /**< Measuret in micro gram per quibik meter air volume */
HomieNode temperatureNode(NODE_TEMPERATUR, "Room Temperature", "number"); HomieNode temperaturNode(NODE_TEMPERATUR, "Room Temperature", "number");
HomieNode pressureNode(NODE_PRESSURE, "Pressure", "number"); HomieNode pressureNode(NODE_PRESSURE, "Pressure", "number");
HomieNode altitudeNode(NODE_ALTITUDE, "Altitude", "number"); HomieNode altitudeNode(NODE_ALTITUDE, "Altitude", "number");
#ifdef BME680
HomieNode gasNode(NODE_GAS, "Gas", "number"); HomieNode gasNode(NODE_GAS, "Gas", "number");
HomieNode humidityNode(NODE_HUMIDITY, "Humidity", "number"); HomieNode humidityNode(NODE_HUMIDITY, "Humidity", "number");
#endif
HomieNode buttonNode(NODE_BUTTON, "Button", "number");
/****************************** Output control ***********************/ /****************************** Output control ***********************/
HomieNode ledStripNode /* to rule them all */("led", "RGB led", "color"); HomieNode ledStripNode /* to rule them all */("led", "RGB led", "color");
/************************** Settings ******************************/ /************************** Settings ******************************/
HomieSetting<bool> i2cEnable("i2c", "BME280 sensor present"); HomieSetting<bool> i2cEnable("i2c",
HomieSetting<bool> rgbTemp("rgbTemp", "Show temperatur via red (>20 °C) and blue (< 20°C)"); #ifdef BME680
"BME680 sensor present"
#else
#ifdef BMP280
"BMP280 sensor present"
#else
"No I2C sensor specified in the project"
#endif
#endif
);
HomieSetting<bool> rgbTemp("rgbTemp", "Show temperature via red (>20 °C) and blue (< 20°C)");
HomieSetting<long> rgbDim("rgbDim", "Factor (1 to 200%) of the status LEDs");
HomieSetting<long> deepsleep("deepsleep", "Amount of seconds to sleep (default 0 - always online, maximum 4294 - 71 minutes)");
static SoftwareSerial pmSerial(SENSOR_PM1006_RX, SENSOR_PM1006_TX); static SoftwareSerial pmSerial(SENSOR_PM1006_RX, SENSOR_PM1006_TX);
Adafruit_BME680 bme(&Wire); // connected via I2C #ifdef BME680
Adafruit_BME680 bmx(&Wire); // connected via I2C
#else
#ifdef BMP280
Adafruit_BMP280 bmx; // connected via I2C
#endif
#endif
Adafruit_NeoPixel strip(PIXEL_COUNT, GPIO_WS2812, NEO_GRB + NEO_KHZ800); Adafruit_NeoPixel strip(PIXEL_COUNT, GPIO_WS2812, NEO_GRB + NEO_KHZ800);
// Variablen // Variablen
uint8_t serialRxBuf[80]; uint8_t serialRxBuf[SERIAL_RCEVBUF_MAX];
uint8_t rxBufIdx = 0; uint8_t rxBufIdx = 0;
int spm25 = 0; int mParticle_pM25 = 0;
int last = 0; int last = 0;
unsigned int mButtonPressed = 0; unsigned int mButtonPressed = 0;
bool mSomethingReceived = false; bool mSomethingReceived = false;
uint32_t mMeasureIndex = 0;
/****************************************************************************** /******************************************************************************
* LOCAL FUNCTIONS * LOCAL FUNCTIONS
*****************************************************************************/ *****************************************************************************/
@ -154,7 +196,12 @@ int getSensorData() {
// Header und Prüfsumme checken // Header und Prüfsumme checken
if (serialRxBuf[0] == 0x16 && serialRxBuf[1] == 0x11 && serialRxBuf[2] == 0x0B /* && checksum == 0 */) if (serialRxBuf[0] == 0x16 && serialRxBuf[1] == 0x11 && serialRxBuf[2] == 0x0B /* && checksum == 0 */)
{ {
return (serialRxBuf[5] << 8 | serialRxBuf[6]); int pmValue = (serialRxBuf[5] << 8 | serialRxBuf[6]);
if (pmValue > PM_MAX) {
return (-1);
} else {
return pmValue;
}
} }
else else
{ {
@ -170,53 +217,84 @@ void onHomieEvent(const HomieEvent &event)
{ {
switch (event.type) switch (event.type)
{ {
case HomieEventType::READY_TO_SLEEP:
if (mOTAactive) {
Homie.getLogger() << "Skip sleeping, as OTA was started" << endl;
return;
} else if (deepsleep.get() > 0) {
long sleepInSeconds = deepsleep.get();
Homie.doDeepSleep(sleepInSeconds * 1000000, RF_NO_CAL);
}
break;
case HomieEventType::MQTT_READY: case HomieEventType::MQTT_READY:
mConnected=true; mConnected=true;
digitalWrite(WITTY_RGB_R, LOW); digitalWrite(WITTY_RGB_R, LOW);
if (!i2cEnable.get()) { /** keep green LED activated to power I2C sensor */ if (!i2cEnable.get()) { /** keep green LED activated to power I2C sensor */
digitalWrite(WITTY_RGB_G, LOW); digitalWrite(WITTY_RGB_G, LOW);
log(MQTT_LEVEL_INFO, F("I2C powersupply deactivated"), MQTT_LOG_I2CINIT);
} }
digitalWrite(WITTY_RGB_B, LOW); digitalWrite(WITTY_RGB_B, LOW);
strip.fill(strip.Color(0,0,128)); /* Update LED only, if not sleeping */
strip.show(); if (deepsleep.get() <= 0) {
strip.fill(strip.Color(0,0,PERCENT2FACTOR(127, rgbDim)));
strip.show();
}
if (mFailedI2Cinitialization) { if (mFailedI2Cinitialization) {
log(MQTT_LEVEL_DEBUG, F("Could not find a valid BME680 sensor, check wiring or " log(MQTT_LEVEL_DEBUG,
"try a different address!"), MQTT_LOG_I2CINIT); #ifdef BME680
"Could not find a valid BME680 sensor, check wiring or try a different address!"
#else
#ifdef BMP280
"Could not find a valid BMP280 sensor, check wiring or try a different address!"
#else
"no I2C sensor defined"
#endif
#endif
, MQTT_LOG_I2CINIT);
} else { } else {
log(MQTT_LEVEL_INFO, F("BME680 sensor found"), MQTT_LOG_I2CINIT); log(MQTT_LEVEL_INFO, F("BME680 sensor found"), MQTT_LOG_I2CINIT);
} }
break; break;
case HomieEventType::READY_TO_SLEEP:
break;
case HomieEventType::OTA_STARTED: case HomieEventType::OTA_STARTED:
mOTAactive = true;
break; break;
case HomieEventType::OTA_SUCCESSFUL: case HomieEventType::OTA_SUCCESSFUL:
ESP.restart(); ESP.restart();
break; break;
case HomieEventType::WIFI_CONNECTED:
digitalWrite(WITTY_RGB_B, HIGH);
break;
default: default:
break; break;
} }
} }
void bmpPublishValues() { void bmpPublishValues() {
#ifdef BME680
// Tell BME680 to begin measurement. // Tell BME680 to begin measurement.
unsigned long endTime = bme.beginReading(); unsigned long endTime = bmx.beginReading();
if (endTime == 0) { if (endTime == 0) {
log(MQTT_LEVEL_ERROR, F("BME680 not accessable"), MQTT_LOG_I2READ); log(MQTT_LEVEL_ERROR, "BMX not accessible", MQTT_LOG_I2READ);
return; return;
} }
temperatureNode.setProperty(NODE_TEMPERATUR).send(String(bme.readTemperature())); #endif
pressureNode.setProperty(NODE_PRESSURE).send(String(bme.readPressure() / 100.0F)); // Publish the values
altitudeNode.setProperty(NODE_ALTITUDE).send(String(bme.readAltitude(SEALEVELPRESSURE_HPA))); temperaturNode.setProperty(NODE_TEMPERATUR).send(String(bmx.readTemperature()));
gasNode.setProperty(NODE_GAS).send(String((bme.gas_resistance / 1000.0))); pressureNode.setProperty(NODE_PRESSURE).send(String(bmx.readPressure() / 100.0F));
altitudeNode.setProperty(NODE_ALTITUDE).send(String(bmx.readAltitude(SEALEVELPRESSURE_HPA)));
humidityNode.setProperty(NODE_HUMIDITY).send(String(bme.humidity)); #ifdef BME680
gasNode.setProperty(NODE_GAS).send(String((bmx.gas_resistance / 1000.0)));
humidityNode.setProperty(NODE_HUMIDITY).send(String(bmx.humidity));
#endif
log(MQTT_LEVEL_DEBUG, String("Temp" + String(bmx.readTemperature()) + "\tPressure:" +
String(bmx.readPressure() / 100.0F) + "\t Altitude:"+
String(bmx.readAltitude(SEALEVELPRESSURE_HPA))), MQTT_LOG_I2READ);
if ( (rgbTemp.get()) && (!mSomethingReceived) ) { if ( (rgbTemp.get()) && (!mSomethingReceived) ) {
if (bme.readTemperature() < TEMPBORDER) { if (bmx.readTemperature() < TEMPBORDER) {
strip.setPixelColor(0, strip.Color(0,0,255)); strip.setPixelColor(0, strip.Color(0,0,PERCENT2FACTOR(127, rgbDim)));
} else { } else {
strip.setPixelColor(0, strip.Color(255,0,0)); strip.setPixelColor(0, strip.Color(PERCENT2FACTOR(127, rgbDim),0,0));
} }
strip.show(); strip.show();
} }
@ -237,16 +315,16 @@ void loopHandler()
{ {
static long lastRead = 0; static long lastRead = 0;
if ((millis() - lastRead) > PM1006_MQTT_UPDATE) { if ((millis() - lastRead) > PM1006_MQTT_UPDATE) {
int pM25 = getSensorData(); mParticle_pM25 = getSensorData();
if (pM25 >= 0) { if (mParticle_pM25 >= 0) {
particle.setProperty(NODE_PARTICLE).send(String(pM25)); particle.setProperty(NODE_PARTICLE).send(String(mParticle_pM25));
if (!mSomethingReceived) { if (!mSomethingReceived) {
if (pM25 < 35) { if (mParticle_pM25 < 35) {
strip.fill(strip.Color(0, 255, 0)); /* green */ strip.fill(strip.Color(0, PERCENT2FACTOR(127, rgbDim), 0)); /* green */
} else if (pM25 < 85) { } else if (mParticle_pM25 < 85) {
strip.fill(strip.Color(255, 127, 0)); /* orange */ strip.fill(strip.Color(PERCENT2FACTOR(127, rgbDim), PERCENT2FACTOR(64, rgbDim), 0)); /* orange */
} else { } else {
strip.fill(strip.Color(255, 0, 0)); /* red */ strip.fill(strip.Color(PERCENT2FACTOR(127, rgbDim), 0, 0)); /* red */
} }
strip.show(); strip.show();
} }
@ -256,9 +334,28 @@ void loopHandler()
if (i2cEnable.get() && (!mFailedI2Cinitialization)) { if (i2cEnable.get() && (!mFailedI2Cinitialization)) {
bmpPublishValues(); bmpPublishValues();
} }
mMeasureIndex++;
/* Clean cycles buttons */
if (mButtonPressed <= BUTTON_MIN_ACTION_CYCLE) {
buttonNode.setProperty(NODE_BUTTON).send("0");
}
lastRead = millis(); lastRead = millis();
/* If nothing needs to be done, sleep and the time is ready for sleeping */
if (mMeasureIndex > MIN_MEASURED_CYCLES && (deepsleep.get() > 0) ) {
Homie.prepareToSleep();
delay(100);
}
} }
/* if the user sees something via the LEDs, inform MQTT, too */
if (mButtonPressed > BUTTON_MIN_ACTION_CYCLE) {
buttonNode.setProperty(NODE_BUTTON).send(String(mButtonPressed));
}
// Feed the dog -> ESP stay alive // Feed the dog -> ESP stay alive
ESP.wdtFeed(); ESP.wdtFeed();
} }
@ -268,23 +365,30 @@ void loopHandler()
bool ledHandler(const HomieRange& range, const String& value) { bool ledHandler(const HomieRange& range, const String& value) {
if (range.isRange) return false; // only one switch is present if (range.isRange) return false; // only one switch is present
mSomethingReceived = true; // Stop animation Homie.getLogger() << "Received: " << (value) << endl;
if (value.equals("250,250,250")) {
int sep1 = value.indexOf(','); mSomethingReceived = false; // enable animation again
int sep2 = value.indexOf(',', sep1 + 1); ledStripNode.setProperty(NODE_AMBIENT).send(value);
if ((sep1 > 0) && (sep2 > 0)) {
int red = value.substring(0,sep1).toInt(); /* OpenHAB hue (0-360°) */
int green = value.substring(sep1 + 1, sep2).toInt(); /* OpenHAB saturation (0-100%) */
int blue = value.substring(sep2 + 1, value.length()).toInt(); /* brightness (0-100%) */
uint8_t r = (red * 255) / 250;
uint8_t g = (green *255) / 250;
uint8_t b = (blue *255) / 250;
uint32_t c = strip.Color(r,g,b);
strip.fill(c);
strip.show();
ledStripNode.setProperty(NODE_AMBIENT).send(String(r) + "," + String(g) + "," + String(b));
return true; return true;
} else {
mSomethingReceived = true; // Stop animation
int sep1 = value.indexOf(',');
int sep2 = value.indexOf(',', sep1 + 1);
if ((sep1 > 0) && (sep2 > 0)) {
int red = value.substring(0,sep1).toInt();
int green = value.substring(sep1 + 1, sep2).toInt();
int blue = value.substring(sep2 + 1, value.length()).toInt();
uint8_t r = (red * 255) / 250;
uint8_t g = (green *255) / 250;
uint8_t b = (blue *255) / 250;
uint32_t c = strip.Color(r,g,b);
strip.fill(c);
strip.show();
ledStripNode.setProperty(NODE_AMBIENT).send(value);
return true;
}
} }
return false; return false;
} }
@ -296,7 +400,7 @@ bool ledHandler(const HomieRange& range, const String& value) {
*****************************************************************************/ *****************************************************************************/
void setup() void setup()
{ {
SPIFFS.begin(); SPIFFS.begin();
Serial.begin(115200); Serial.begin(115200);
Serial.setTimeout(2000); Serial.setTimeout(2000);
@ -312,13 +416,19 @@ void setup()
Homie.onEvent(onHomieEvent); Homie.onEvent(onHomieEvent);
i2cEnable.setDefaultValue(false); i2cEnable.setDefaultValue(false);
rgbTemp.setDefaultValue(false); rgbTemp.setDefaultValue(false);
memset(serialRxBuf, 0, 80); rgbDim.setDefaultValue(100).setValidator([] (long candidate) {
return (candidate > 1) && (candidate <= 200);
});
deepsleep.setDefaultValue(0).setValidator([] (long candidate) {
return ((candidate >= 0) && (candidate < 4294)); /* between 0 (deactivated) and 71 minutes */
});
memset(serialRxBuf, 0, SERIAL_RCEVBUF_MAX);
pmSerial.begin(PM1006_BIT_RATE); pmSerial.begin(PM1006_BIT_RATE);
Homie.setup(); Homie.setup();
particle.advertise(NODE_PARTICLE).setName("Particle").setDatatype(NUMBER_TYPE).setUnit("micro gram per quibik"); particle.advertise(NODE_PARTICLE).setName("Particle").setDatatype(NUMBER_TYPE).setUnit("micro gram per quibik");
temperatureNode.advertise(NODE_TEMPERATUR).setName("Degrees") temperaturNode.advertise(NODE_TEMPERATUR).setName("Degrees")
.setDatatype("float") .setDatatype("float")
.setUnit("ºC"); .setUnit("ºC");
pressureNode.advertise(NODE_PRESSURE).setName("Pressure") pressureNode.advertise(NODE_PRESSURE).setName("Pressure")
@ -327,47 +437,70 @@ void setup()
altitudeNode.advertise(NODE_ALTITUDE).setName("Altitude") altitudeNode.advertise(NODE_ALTITUDE).setName("Altitude")
.setDatatype("float") .setDatatype("float")
.setUnit("m"); .setUnit("m");
#ifdef BME680
gasNode.advertise(NODE_GAS).setName("Gas") gasNode.advertise(NODE_GAS).setName("Gas")
.setDatatype("float") .setDatatype("float")
.setUnit(" KOhms"); .setUnit(" KOhms");
humidityNode.advertise(NODE_HUMIDITY).setName("Humidity") humidityNode.advertise(NODE_HUMIDITY).setName("Humidity")
.setDatatype("float") .setDatatype("float")
.setUnit("%"); .setUnit("%");
#endif
ledStripNode.advertise(NODE_AMBIENT).setName("All Leds") ledStripNode.advertise(NODE_AMBIENT).setName("All Leds")
.setDatatype("color").setFormat("rgb") .setDatatype("color").setFormat("rgb")
.settable(ledHandler); .settable(ledHandler);
buttonNode.advertise(NODE_BUTTON).setName("Button pressed")
.setDatatype("integer");
strip.begin(); strip.begin();
/* activate I2C for BOSCH sensor */
Wire.begin(SENSOR_I2C_SDI, SENSOR_I2C_SCK);
mConfigured = Homie.isConfigured(); mConfigured = Homie.isConfigured();
digitalWrite(WITTY_RGB_G, HIGH); digitalWrite(WITTY_RGB_G, HIGH);
if (mConfigured) if (mConfigured)
{ {
if (i2cEnable.get()) { if (i2cEnable.get()) {
strip.fill(strip.Color(0,128,0)); #ifdef BME680
strip.show(); printf("Wait 1 second...\r\n");
delay(1000);
#endif
/* activate I2C for BOSCH sensor */
Wire.begin(SENSOR_I2C_SDI, SENSOR_I2C_SCK);
printf("Wait 50 milliseconds...\r\n");
delay(50);
/* Extracted from library's example */ /* Extracted from library's example */
mFailedI2Cinitialization = !bme.begin(); mFailedI2Cinitialization = !bmx.begin();
if (!mFailedI2Cinitialization) { if (!mFailedI2Cinitialization) {
bme.setTemperatureOversampling(BME680_OS_8X); strip.fill(strip.Color(0,PERCENT2FACTOR(64, rgbDim),0));
bme.setHumidityOversampling(BME680_OS_2X); strip.show();
bme.setPressureOversampling(BME680_OS_4X); #ifdef BME680
bme.setIIRFilterSize(BME680_FILTER_SIZE_3); bmx.setTemperatureOversampling(BME680_OS_8X);
bme.setGasHeater(320, 150); // 320*C for 150 ms bmx.setHumidityOversampling(BME680_OS_2X);
bmx.setPressureOversampling(BME680_OS_4X);
bmx.setIIRFilterSize(BME680_FILTER_SIZE_3);
bmx.setGasHeater(320, 150); // 320*C for 150 ms
#endif
#ifdef BMP280
/* Default settings from datasheet. */
bmx.setSampling(Adafruit_BMP280::MODE_NORMAL, /* Operating Mode. */
Adafruit_BMP280::SAMPLING_X2, /* Temp. oversampling */
Adafruit_BMP280::SAMPLING_X16, /* Pressure oversampling */
Adafruit_BMP280::FILTER_X16, /* Filtering. */
Adafruit_BMP280::STANDBY_MS_500); /* Standby time. */
#endif
printf("Sensor found on I2C bus\r\n");
} else { } else {
printf("Faild to initialize I2C bus\r\n"); printf("Failed to initialize I2C bus\r\n");
} }
} }
strip.fill(strip.Color(0,0,0)); /* Nothing when sleeping */
for (int i=0;i < (PIXEL_COUNT / 2); i++) { if (deepsleep.get() <= 0) {
strip.setPixelColor(0, strip.Color(0,0,128)); strip.fill(strip.Color(0,0,0));
for (int i=0;i < (PIXEL_COUNT / 2); i++) {
strip.setPixelColor(0, strip.Color(0,0,128 * rgbDim.get()));
}
strip.show();
} }
strip.show();
digitalWrite(WITTY_RGB_B, HIGH);
} else { } else {
digitalWrite(WITTY_RGB_R, HIGH);
strip.fill(strip.Color(128,0,0)); strip.fill(strip.Color(128,0,0));
for (int i=0;i < (PIXEL_COUNT / 2); i++) { for (int i=0;i < (PIXEL_COUNT / 2); i++) {
strip.setPixelColor(0, strip.Color(0,0,128)); strip.setPixelColor(0, strip.Color(0,0,128));
@ -381,19 +514,36 @@ void loop()
Homie.loop(); Homie.loop();
/* use the pin, receiving the soft serial additionally as button */ /* use the pin, receiving the soft serial additionally as button */
if (digitalRead(GPIO_BUTTON) == LOW) { if (digitalRead(GPIO_BUTTON) == LOW) {
mButtonPressed++; if ((millis() - mLastButtonAction) > BUTTON_CHECK_INTERVALL) {
mButtonPressed++;
}
if (mButtonPressed > BUTTON_MIN_ACTION_CYCLE) {
digitalWrite(WITTY_RGB_R, HIGH);
digitalWrite(WITTY_RGB_B, LOW);
strip.fill(strip.Color(0,0,0));
strip.setPixelColor(0, strip.Color((mButtonPressed % 100),0,0));
strip.setPixelColor(1, strip.Color((mButtonPressed / 100),0,0));
strip.setPixelColor(2, strip.Color((mButtonPressed / 100),0,0));
strip.show();
}
} else { } else {
mButtonPressed=0U; mButtonPressed=0U;
digitalWrite(WITTY_RGB_R, LOW);
} }
if (mButtonPressed > 10000U) { if (mButtonPressed > BUTTON_MAX_CYCLE) {
mButtonPressed=0U;
if (SPIFFS.exists("/homie/config.json")) { if (SPIFFS.exists("/homie/config.json")) {
strip.fill(strip.Color(0,PERCENT2FACTOR(127, rgbDim),0));
strip.show();
printf("Resetting config\r\n"); printf("Resetting config\r\n");
SPIFFS.remove("/homie/config.json"); SPIFFS.remove("/homie/config.json");
SPIFFS.end(); SPIFFS.end();
delay(50);
Homie.reboot();
} else { } else {
printf("No config present\r\n"); printf("No config present\r\n");
strip.fill(strip.Color(0,0,128));
strip.show();
} }
} }
} }
@ -414,4 +564,5 @@ void log(int level, String message, int statusCode)
Homie.getMqttClient().publish(logTopic, 2, false, buffer.c_str()); Homie.getMqttClient().publish(logTopic, 2, false, buffer.c_str());
delete logTopic; delete logTopic;
} }
Homie.getLogger() << (level) << "@" << (statusCode) << " " << (message) << endl;
} }