Compare commits

..

25 Commits

Author SHA1 Message Date
Ollo
832e5def65 Show PM2.5 at diagrams, too 2021-12-18 22:37:58 +01:00
Ollo
2efa4a576c Use real data for the diagram 2021-12-18 22:16:47 +01:00
Ollo
ca8da3c608 Always start webserver 2021-12-18 21:53:29 +01:00
Ollo
2c884710c1 In standalone mode, do not allocate the memory, necessary to read the sensors 2021-12-18 21:44:49 +01:00
Ollo
a3be4f19a1 Seperate webpage for the diagram 2021-12-18 13:41:51 +01:00
Ollo
ae6c53d39b Generate the JSON without any library 2021-12-18 13:29:41 +01:00
Ollo
3224224251 Generate dynamic diagram content 2021-12-17 21:43:49 +01:00
Ollo
fc5444f8b3 Multiple parameter in one diagram 2021-12-17 20:59:34 +01:00
Ollo
5955ca1a5c New HTTP endpoints: /header and /datasets 2021-12-16 20:40:44 +01:00
Ollo
2b930a6902 Without MQTT no publish 2021-12-16 20:24:51 +01:00
Ollo
128d5a0b3b Chart example on ESP8266 2021-12-16 20:21:24 +01:00
Ollo
c26ee6342c Prepared chart example 2021-12-15 21:20:27 +01:00
Ollo
32e868b176 Reduce cycle time 2021-12-15 20:22:48 +01:00
Ollo
797a6dbe05 Reduce cycle time 2021-12-15 20:17:09 +01:00
Ollo
fc185b4bca Merged brightness configuration into standalone stream 2021-12-15 17:31:02 +01:00
Ollo
24e6bfd6f9 Merged swapped pins for I2C sensor 2021-12-12 17:59:20 +01:00
Ollo
81e4f9901c Always wait for I2C 2021-12-12 15:40:35 +01:00
Ollo
5e27d3ebf4 specific message for each Bosch sensor 2021-12-12 15:28:24 +01:00
Ollo
b91317fae2 Merged from master 2021-12-12 15:19:10 +01:00
Ollo
95b6fcef06 both BMx sensors supported 2021-12-06 21:28:12 +01:00
Ollo
41ebed2b27 Start webserver only in standalone-mode 2021-11-28 14:27:14 +01:00
Ollo
81adc9bd61 Automatic refresh; alternating background colors 2021-11-28 14:07:36 +01:00
Ollo
ca811a9abe JSON is shown on website 2021-11-28 13:59:49 +01:00
Ollo
73f637d6ec Sensor values are published as JSON in nonMQTT mode 2021-11-27 17:08:03 +01:00
Ollo
29beff5e82 Webserver is running 2021-11-27 16:19:35 +01:00
7 changed files with 380 additions and 67 deletions

View File

@ -54,7 +54,15 @@ The following pins are used:
* BMP280 sensor * BMP280 sensor
* some wire * some wire
# Webserver
This version has a webserver activated, if MQTT server is set to **localhost**.
Every 20 seconds a measurement is performed.
This is shown in a diagram via chart.js
# Sources # Sources
For the Witty board For the Witty board
* [https://github.com/amkuipers/witty Witty pinout] * [https://github.com/amkuipers/witty Witty pinout]
* [https://arduino.ua/products_pictures/large_AOC361-5.jpg Schematics] * [https://arduino.ua/products_pictures/large_AOC361-5.jpg Schematics]
* [https://www.chartjs.org/docs/latest/getting-started/integration.html]

37
data/chart.htm Normal file
View File

@ -0,0 +1,37 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>IKEA Home Sensor Diagram</title>
<script src="/chart.min.js"></script>
<script type="text/javascript">
function onBodyLoad(){
const xhttp = new XMLHttpRequest();
xhttp.responseType = 'json';
xhttp.onload = function() {
var jsonResponse = this.response;
console.log("JSON received");
const ctx = document.getElementById('myChart');
const myChart = new Chart(ctx, {
type: 'line',
data: jsonResponse,
options: {
scales: {
y: {
beginAtZero: false
}
}
}
});
console.log("Diagram generated");
}
xhttp.open("GET", "/diagram", true);
xhttp.send();
}
</script>
</head>
<body id="body" onload="onBodyLoad()">
<canvas id="myChart" width="100%" height="100"></canvas>
</body>
</html>

13
data/chart.min.js vendored Normal file

File diff suppressed because one or more lines are too long

96
data/standalone.htm Normal file
View File

@ -0,0 +1,96 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>IKEA Home Sensor</title>
<style type="text/css">
tr.heading td {
background-color: black; color: white;
}
tr.d0 td {
background-color: #ffffff; color: black;
}
tr.d1 td {
background-color: #b8b8b8; color: black;
}
</style>
<script type="text/javascript">
function mySensorTimer(){
const xhttp = new XMLHttpRequest();
xhttp.responseType = 'json';
xhttp.onload = function() {
var jsonResponse = this.response;
document.getElementById("temp").innerHTML = jsonResponse.temp
document.getElementById("altitude").innerHTML = jsonResponse.altitude;
document.getElementById("pressure").innerHTML = jsonResponse.pressure;
document.getElementById("particle").innerHTML = jsonResponse.particle;
if (jsonResponse.gas) {
document.getElementById("gas").innerHTML = jsonResponse.gas;
} else {
document.getElementById("rowGas").hidden = true;
}
if (jsonResponse.humidity) {
document.getElementById("humidity").innerHTML = jsonResponse.humidity;
} else {
document.getElementById("rowHumidity").hidden = true;
}
console.log(this.responseText);
}
xhttp.open("GET", "/sensors", true);
xhttp.send();
}
function onBodyLoad(){
setInterval(mySensorTimer, 5000);
}
</script>
</head>
<body id="body" onload="onBodyLoad()">
<h1>Room Sensor</h1>
<table>
<thead>
<tr class="heading">
<td>Sensor</td>
<td>Value</td>
<td></td>
</tr>
</thead>
<tbody>
<tr class="d0">
<td>Temperatur</td>
<td id="temp">temp</td>
<td>°C</td>
</tr>
<tr id="rowHumidity" class="d1">
<td>Humidity</td>
<td id="humidity">humidity</td>
<td>%</td>
</tr>
<tr id="rowGas" class="d0">
<td>Gas</td>
<td id="gas">gas</td>
<td> KOhms</td>
</tr>
<tr class="d1">
<td>Altitude</td>
<td id="altitude">altitude</td>
<td>m</td>
</tr>
<tr class="d0">
<td>Pressure</td>
<td id="pressure">pressure</td>
<td>hPa</td>
</tr>
<tr class="d1">
<td>Particle</td>
<td id="particle">particle</td>
<td>micro gram per quibik</td>
</tr>
</tbody>
</table>
<h1>Diagram</h1>
<p>
Can be found on the <a href="chart.htm">next page</a>.
</p>
</body>
</html>

View File

@ -13,6 +13,6 @@
#define HOMIE_SETTINGS #define HOMIE_SETTINGS
#define HOMIE_FIRMWARE_NAME "RoomSensor" #define HOMIE_FIRMWARE_NAME "RoomSensor"
#define HOMIE_FIRMWARE_VERSION "2.3.0" #define HOMIE_FIRMWARE_VERSION "2.2.0"
#endif #endif

View File

@ -12,7 +12,7 @@
platform = espressif8266 platform = espressif8266
board = d1_mini board = d1_mini
framework = arduino framework = arduino
build_flags = -D PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY -D BME680 build_flags = -D PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY -DBMP280
; build_flag needs define the Bosch sensor... ; build_flag needs define the Bosch sensor...
; -D BMP280 ; -D BMP280
;or ;or
@ -25,4 +25,4 @@ lib_deps = https://github.com/homieiot/homie-esp8266.git#develop
adafruit/Adafruit BMP280 Library @ ^2.4.2 adafruit/Adafruit BMP280 Library @ ^2.4.2
adafruit/Adafruit BME680 Library @ ^2.0.1 adafruit/Adafruit BME680 Library @ ^2.0.1
upload_port = /dev/ttyUSB0 upload_port = /dev/ttyUSB1

View File

@ -20,7 +20,7 @@
#include <Adafruit_Sensor.h> #include <Adafruit_Sensor.h>
#ifdef BME680 #ifdef BME680
#include "Adafruit_BME680.h" #include "Adafruit_BME680.h"
#else #else
#ifdef BMP280 #ifdef BMP280
#include "Adafruit_BMP280.h" #include "Adafruit_BMP280.h"
#else #else
@ -51,9 +51,6 @@
#define BUTTON_MIN_ACTION_CYCLE 55U /**< Minimum cycle to react on the button (e.g. 5 second) */ #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 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
@ -84,12 +81,29 @@
#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 NODE_BUTTON "button"
#define PORTNUMBER_HTTP 80 /**< IANA TCP/IP port number, used for HTTP / web traffic */
#define SERIAL_RCEVBUF_MAX 80 /**< Maximum 80 characters can be received from the PM1006 sensor */ #define SERIAL_RCEVBUF_MAX 80 /**< Maximum 80 characters can be received from the PM1006 sensor */
#define MEASURE_POINT_MAX 1024 /**< Amount of measure point, that can be stored */
/****************************************************************************** /******************************************************************************
* TYPE DEFS * TYPE DEFS
******************************************************************************/ ******************************************************************************/
typedef struct s_point {
long timestamp;
float temp;
#ifdef BME680
uint32_t gas;
float humidity;
#endif
float pressure;
int pm25;
} sensor_point;
/****************************************************************************** /******************************************************************************
* FUNCTION PROTOTYPES * FUNCTION PROTOTYPES
******************************************************************************/ ******************************************************************************/
@ -102,8 +116,8 @@ 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;
AsyncWebServer* mHttp = NULL;
long mLastButtonAction = 0; long mLastButtonAction = 0;
/******************************* Sensor data **************************/ /******************************* Sensor data **************************/
@ -135,7 +149,6 @@ HomieSetting<bool> i2cEnable("i2c",
); );
HomieSetting<bool> rgbTemp("rgbTemp", "Show temperature via red (>20 °C) and blue (< 20°C)"); 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> 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);
#ifdef BME680 #ifdef BME680
@ -155,7 +168,9 @@ int mParticle_pM25 = 0;
int last = 0; int last = 0;
unsigned int mButtonPressed = 0; unsigned int mButtonPressed = 0;
bool mSomethingReceived = false; bool mSomethingReceived = false;
bool mConnectedNonMQTT = false;
sensor_point* mMeasureSeries;
uint32_t mMeasureIndex = 0; uint32_t mMeasureIndex = 0;
/****************************************************************************** /******************************************************************************
@ -196,12 +211,7 @@ 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 */)
{ {
int pmValue = (serialRxBuf[5] << 8 | serialRxBuf[6]); return (serialRxBuf[5] << 8 | serialRxBuf[6]);
if (pmValue > PM_MAX) {
return (-1);
} else {
return pmValue;
}
} }
else else
{ {
@ -217,29 +227,22 @@ void onHomieEvent(const HomieEvent &event)
{ {
switch (event.type) switch (event.type)
{ {
case HomieEventType::READY_TO_SLEEP: case HomieEventType::WIFI_CONNECTED:
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:
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); log(MQTT_LEVEL_INFO, F("I2C powersupply deactivated"), MQTT_LOG_I2CINIT);
} }
digitalWrite(WITTY_RGB_B, LOW); digitalWrite(WITTY_RGB_B, LOW);
/* Update LED only, if not sleeping */ strip.fill(strip.Color(0,0,128));
if (deepsleep.get() <= 0) { strip.show();
strip.fill(strip.Color(0,0,PERCENT2FACTOR(127, rgbDim))); if (mHttp != NULL) {
strip.show(); strip.fill(strip.Color(0,64,0));
mConnectedNonMQTT = true;
} }
break;
case HomieEventType::MQTT_READY:
mConnected=true;
if (mFailedI2Cinitialization) { if (mFailedI2Cinitialization) {
log(MQTT_LEVEL_DEBUG, log(MQTT_LEVEL_DEBUG,
#ifdef BME680 #ifdef BME680
@ -256,29 +259,42 @@ void onHomieEvent(const HomieEvent &event)
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 updateLEDs() {
#ifdef BME680 #ifdef BME680
// Tell BME680 to begin measurement. // Tell BME680 to begin measurement.
unsigned long endTime = bmx.beginReading(); unsigned long endTime = bmx.beginReading();
if (endTime == 0) { if (endTime == 0) {
log(MQTT_LEVEL_ERROR, "BMX not accessible", MQTT_LOG_I2READ); log(MQTT_LEVEL_ERROR, "BME680 not accessible", MQTT_LOG_I2READ);
return; return;
} }
#endif #endif
if ( (rgbTemp.get()) && (!mSomethingReceived) ) {
if (bmx.readTemperature() < TEMPBORDER) {
strip.setPixelColor(0, strip.Color(0,0,255));
} else {
strip.setPixelColor(0, strip.Color(255,0,0));
}
strip.show();
} else {
#ifdef BME680
bmx.performReading();
#endif
}
}
void bmpPublishValues() {
// Publish the values // Publish the values
temperaturNode.setProperty(NODE_TEMPERATUR).send(String(bmx.readTemperature())); temperaturNode.setProperty(NODE_TEMPERATUR).send(String(bmx.readTemperature()));
pressureNode.setProperty(NODE_PRESSURE).send(String(bmx.readPressure() / 100.0F)); pressureNode.setProperty(NODE_PRESSURE).send(String(bmx.readPressure() / 100.0F));
@ -300,6 +316,130 @@ void bmpPublishValues() {
} }
} }
/**
* @brief Generate JSON with last measured values
* For the update interval, please check @see PM1006_MQTT_UPDATE
* @return String with JSON
*/
String sensorAsJSON(void) {
String buffer;
StaticJsonDocument<500> doc;
if (mMeasureIndex > 0) {
int lastIdx = mMeasureIndex - 1;
doc["temp"] = String(mMeasureSeries[lastIdx].temp);
#ifdef BME680
doc["gas"] = String(mMeasureSeries[lastIdx].gas);
doc["humidity"] = String(mMeasureSeries[lastIdx].humidity);
#endif
float atmospheric = mMeasureSeries[lastIdx].pressure;
float altitude = 44330.0 * (1.0 - pow(atmospheric / SEALEVELPRESSURE_HPA, 0.1903));
doc["altitude"] = String(altitude);
doc["pressure"] = String(atmospheric);
doc["particle"] = String(mMeasureSeries[lastIdx].pm25);
}
doc["cycle"] = String(mMeasureIndex);
serializeJson(doc, buffer);
return buffer;
}
/**
* @brief Generate JSON with all available sensors
*
* @return String
*/
String sensorHeader(void) {
String buffer;
StaticJsonDocument<500> doc;
doc.add("milli");
doc.add("temp");
#ifdef BME680
doc.add("gas");
doc.add("humidity");
#endif
doc.add("altitude");
doc.add("pressure");
doc.add("particle");
serializeJson(doc, buffer);
return buffer;
}
/**
* @brief Generate JSON with all sensor values
* Array of JSON with all measured elements to show in the web browser.
* Example:
* <code>
* dynamicData = {
* labels: [ "0", "-30", "-60", "-90", "-120", "-160" ],
* datasets: [{
* label: 'temp',
* data: [24, 22, 23, 25, 22, 23],
* borderColor: "rgba(255,0,0,1)"
* }, {
* label: 'pressure',
* data: [1000, 1002, 1003, 999, 996, 1000],
* borderColor: "rgba(0,0,255,1)"
* }
* ]
* }
* </code>
*
* @return String
*/
String diagramJson(void) {
int i;
String buffer;
String bufferLabels = "\"\"";
String bufferDataTemp = "\"\"";
String bufferDataPressure = "\"\"";
String bufferDataPM = "\"\"";
String bufferDatasets;
String bufferData;
if (mMeasureSeries == NULL) {
buffer = "{ \"error\": \"Malloc failed\" }";
return buffer;
}
long now = millis();
if (mMeasureIndex > 0) {
bufferLabels = "[ \"" + String((now - mMeasureSeries[0].timestamp) / 1000) + "s";
bufferDataTemp = "[ \"" + String(mMeasureSeries[0].temp);
bufferDataPressure = "[ \"" + String(mMeasureSeries[0].pressure);
bufferDataPM = "[ \"" + String(mMeasureSeries[0].pm25);
}
for(i=1; i < mMeasureIndex; i++) {
bufferLabels += "\", \"" + String((now - mMeasureSeries[i].timestamp) / 1000) + "s";
bufferDataTemp += "\", \"" + String(mMeasureSeries[i].temp);
bufferDataPressure += "\", \"" + String(mMeasureSeries[i].pressure);
bufferDataPM += "\", \"" + String(mMeasureSeries[i].pm25);
}
if (mMeasureIndex > 0) {
bufferLabels += "\" ]";
bufferDataTemp += "\" ]";
bufferDataPressure += "\" ]";
bufferDataPM += "\" ]";
}
/* Generate label */
buffer = "{ \"labels\" : " + bufferLabels + ",\n";
buffer += "\"datasets\" : [";
/* generate first block for Temperature */
buffer += "{\n \"label\" : \"Temp\",\n \"data\" : " + bufferDataTemp + ",\n \"borderColor\" : \"rgba(255,0,0,1)\" \n}";
/* generate second block for Pressure */
buffer += ", ";
buffer += "{\n \"label\" : \"Pressure\",\n \"data\" : " + bufferDataPressure + ",\n \"borderColor\" : \"rgba(0,0,255,1)\" \n}";
/* generate third block for PM2.5 values */
buffer += ", ";
buffer += "{\n \"label\" : \"PM 2.5\",\n \"data\" : " + bufferDataPM + ",\n \"borderColor\" : \"rgba(0,255,0,1)\" \n}";
/* TODO, next ones ... */
buffer += "]\n }";
return buffer;
}
/** /**
* @brief Main loop, triggered by the Homie API * @brief Main loop, triggered by the Homie API
* All logic needs to be done here. * All logic needs to be done here.
@ -317,7 +457,9 @@ void loopHandler()
if ((millis() - lastRead) > PM1006_MQTT_UPDATE) { if ((millis() - lastRead) > PM1006_MQTT_UPDATE) {
mParticle_pM25 = getSensorData(); mParticle_pM25 = getSensorData();
if (mParticle_pM25 >= 0) { if (mParticle_pM25 >= 0) {
if (!mConnectedNonMQTT) {
particle.setProperty(NODE_PARTICLE).send(String(mParticle_pM25)); particle.setProperty(NODE_PARTICLE).send(String(mParticle_pM25));
}
if (!mSomethingReceived) { if (!mSomethingReceived) {
if (mParticle_pM25 < 35) { if (mParticle_pM25 < 35) {
strip.fill(strip.Color(0, PERCENT2FACTOR(127, rgbDim), 0)); /* green */ strip.fill(strip.Color(0, PERCENT2FACTOR(127, rgbDim), 0)); /* green */
@ -332,27 +474,35 @@ void loopHandler()
/* Read BOSCH sensor */ /* Read BOSCH sensor */
if (i2cEnable.get() && (!mFailedI2Cinitialization)) { if (i2cEnable.get() && (!mFailedI2Cinitialization)) {
bmpPublishValues(); updateLEDs();
if (!mConnectedNonMQTT) {
bmpPublishValues();
}
} }
mMeasureIndex++; // FIXME: add the measured data into the big list
if (mMeasureSeries != NULL) {
mMeasureSeries[mMeasureIndex].timestamp = millis();
mMeasureSeries[mMeasureIndex].temp = bmx.readTemperature();
#ifdef BME680
mMeasureSeries[mMeasureIndex].gas = (bmx.gas_resistance / 1000.0);
mMeasureSeries[mMeasureIndex].humidity = bmx.humidity;
#endif
float atmospheric = bmx.readPressure() / 100.0F;
mMeasureSeries[mMeasureIndex].pressure = atmospheric;
mMeasureSeries[mMeasureIndex].pm25 = mParticle_pM25;
mMeasureIndex++;
}
/* Clean cycles buttons */ /* Clean cycles buttons */
if (mButtonPressed <= BUTTON_MIN_ACTION_CYCLE) { if ((!mConnectedNonMQTT) && (mButtonPressed <= BUTTON_MIN_ACTION_CYCLE)) {
buttonNode.setProperty(NODE_BUTTON).send("0"); 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 the user sees something via the LEDs, inform MQTT, too */
if (mButtonPressed > BUTTON_MIN_ACTION_CYCLE) { if ((!mConnectedNonMQTT) && (mButtonPressed > BUTTON_MIN_ACTION_CYCLE)) {
buttonNode.setProperty(NODE_BUTTON).send(String(mButtonPressed)); buttonNode.setProperty(NODE_BUTTON).send(String(mButtonPressed));
} }
@ -393,8 +543,6 @@ bool ledHandler(const HomieRange& range, const String& value) {
return false; return false;
} }
/****************************************************************************** /******************************************************************************
* GLOBAL FUNCTIONS * GLOBAL FUNCTIONS
*****************************************************************************/ *****************************************************************************/
@ -414,14 +562,11 @@ void setup()
Homie_setFirmware(HOMIE_FIRMWARE_NAME, HOMIE_FIRMWARE_VERSION); Homie_setFirmware(HOMIE_FIRMWARE_NAME, HOMIE_FIRMWARE_VERSION);
Homie.setLoopFunction(loopHandler); Homie.setLoopFunction(loopHandler);
Homie.onEvent(onHomieEvent); Homie.onEvent(onHomieEvent);
i2cEnable.setDefaultValue(false); i2cEnable.setDefaultValue(true);
rgbTemp.setDefaultValue(false); rgbTemp.setDefaultValue(false);
rgbDim.setDefaultValue(100).setValidator([] (long candidate) { rgbDim.setDefaultValue(100).setValidator([] (long candidate) {
return (candidate > 1) && (candidate <= 200); 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); memset(serialRxBuf, 0, SERIAL_RCEVBUF_MAX);
pmSerial.begin(PM1006_BIT_RATE); pmSerial.begin(PM1006_BIT_RATE);
@ -457,6 +602,8 @@ void setup()
digitalWrite(WITTY_RGB_G, HIGH); digitalWrite(WITTY_RGB_G, HIGH);
if (mConfigured) if (mConfigured)
{ {
mMeasureSeries = (sensor_point *) malloc(sizeof(sensor_point) * MEASURE_POINT_MAX);
memset(mMeasureSeries, 0, sizeof(sensor_point) * MEASURE_POINT_MAX);
if (i2cEnable.get()) { if (i2cEnable.get()) {
#ifdef BME680 #ifdef BME680
printf("Wait 1 second...\r\n"); printf("Wait 1 second...\r\n");
@ -491,27 +638,39 @@ void setup()
printf("Failed to initialize I2C bus\r\n"); printf("Failed to initialize I2C bus\r\n");
} }
} }
/* Nothing when sleeping */ strip.fill(strip.Color(0,0,0));
if (deepsleep.get() <= 0) {
strip.fill(strip.Color(0,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 * rgbDim.get())); strip.setPixelColor(0, strip.Color(0,128,0));
} }
strip.show(); mHttp = new AsyncWebServer(PORTNUMBER_HTTP);
} mHttp->on("/heap", HTTP_GET, [](AsyncWebServerRequest *request){
} else { request->send(200, "text/plain", String(ESP.getFreeHeap()));
digitalWrite(WITTY_RGB_R, HIGH); });
strip.fill(strip.Color(128,0,0)); mHttp->on("/sensors", HTTP_GET, [](AsyncWebServerRequest *request){
for (int i=0;i < (PIXEL_COUNT / 2); i++) { request->send(200, "application/json", sensorAsJSON());
strip.setPixelColor(0, strip.Color(0,0,128)); });
} mHttp->on("/header", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(200, "application/json", sensorHeader());
});
mHttp->on("/diagram", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(200, "application/json", diagramJson());
});
mHttp->serveStatic("/", SPIFFS, "/").setDefaultFile("standalone.htm");
mHttp->begin();
Homie.getLogger() << "Webserver started" << endl;
strip.show(); strip.show();
} }
} }
void loop() void loop()
{ {
Homie.loop(); if (!mConnectedNonMQTT) {
Homie.loop();
} else {
/* call the custom loop directly, as Homie is deactivated */
loopHandler();
}
/* 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) {
if ((millis() - mLastButtonAction) > BUTTON_CHECK_INTERVALL) { if ((millis() - mLastButtonAction) > BUTTON_CHECK_INTERVALL) {