Compare commits
3 Commits
67a1a317fc
...
75755ada63
| Author | SHA1 | Date | |
|---|---|---|---|
| 75755ada63 | |||
| 118bef8f72 | |||
| 528c12c70f |
@ -7,25 +7,205 @@
|
||||
<style>
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
font-size: 4vw;
|
||||
margin: 1em;
|
||||
font-size: 12vw;
|
||||
margin: 0;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
background-color: #5c875c;
|
||||
}
|
||||
|
||||
div {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
h1 {
|
||||
.heading {
|
||||
padding: 0.25em 0;
|
||||
text-align: center;
|
||||
background-color: #93da93;
|
||||
border-bottom: 1px solid gray;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 0.25em;
|
||||
}
|
||||
|
||||
.section {
|
||||
clear: both;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 50%;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.valueAndUnit {
|
||||
clear: both;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.value {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.unit {
|
||||
float: left;
|
||||
margin-left: 0.25em;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.inputNull {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.inputBlue {
|
||||
color: blue;
|
||||
}
|
||||
|
||||
.inputGreen {
|
||||
color: #00ff00;
|
||||
}
|
||||
|
||||
.inputRed {
|
||||
color: #ba0000;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Gewächshaus</h1>
|
||||
TODO
|
||||
<div class="heading">Gewächshaus</div>
|
||||
|
||||
<div class="content">
|
||||
|
||||
<div class="section">
|
||||
<div class="title">Temperatur</div>
|
||||
<div class="valueAndUnit">
|
||||
<div class="value" id="temperature"></div>
|
||||
<div class="unit">°C</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<div class="title">Relative Luftfeuchte</div>
|
||||
<div class="valueAndUnit">
|
||||
<div class="value" id="relative"></div>
|
||||
<div class="unit">%</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<div class="title">Absolute Luftfeuchte</div>
|
||||
<div class="valueAndUnit">
|
||||
<div class="value" id="absolute"></div>
|
||||
<div class="unit">g/m³</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<div class="title">Helligkeit</div>
|
||||
<div class="valueAndUnit">
|
||||
<div class="value" id="illuminance"></div>
|
||||
<div class="unit">lux</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const NO_VALUE = "- - -";
|
||||
|
||||
const TEMPERATURE_BLUE = 10;
|
||||
const TEMPERATURE_RED = 35;
|
||||
|
||||
const RELATIVE_BLUE = 60;
|
||||
const RELATIVE_RED = 80;
|
||||
|
||||
const htmlTemperature = document.getElementById('temperature');
|
||||
const htmlRelative = document.getElementById('relative');
|
||||
const htmlAbsolute = document.getElementById('absolute');
|
||||
const htmlIlluminance = document.getElementById('illuminance');
|
||||
|
||||
function status() {
|
||||
get("/status");
|
||||
}
|
||||
|
||||
function get(path) {
|
||||
const request = new XMLHttpRequest();
|
||||
request.onreadystatechange = function () {
|
||||
if (request.readyState === 4) {
|
||||
update(request.responseText);
|
||||
}
|
||||
};
|
||||
request.open('GET', (location.hostname === "localhost" ? "http://10.0.0.160" : "") + path);
|
||||
request.send();
|
||||
}
|
||||
|
||||
function format(value, decimals) {
|
||||
return value?.toLocaleString(undefined, {minimumFractionDigits: decimals, maximumFractionDigits: decimals});
|
||||
}
|
||||
|
||||
function update(response) {
|
||||
try {
|
||||
const data = JSON.parse(response);
|
||||
htmlTemperature.innerText = format(data?.temperature, 1) || NO_VALUE;
|
||||
htmlRelative.innerText = format(data?.relative, 0) || NO_VALUE;
|
||||
htmlAbsolute.innerText = format(data?.absolute, 1) || NO_VALUE;
|
||||
htmlIlluminance.innerText = format(data?.illuminance, 0) || NO_VALUE;
|
||||
|
||||
const relativeNull = !isSet(data?.relative);
|
||||
const relativeBlue = !relativeNull && data?.relative < RELATIVE_BLUE;
|
||||
const relativeRed = !relativeNull && data?.relative > RELATIVE_RED;
|
||||
const relativeGreen = !relativeNull && !relativeBlue && !relativeRed;
|
||||
setClass(htmlRelative.parentElement, "inputNull", relativeNull);
|
||||
setClass(htmlRelative.parentElement, "inputRed", relativeBlue);
|
||||
setClass(htmlRelative.parentElement, "inputGreen", relativeGreen);
|
||||
setClass(htmlRelative.parentElement, "inputBlue", relativeRed);
|
||||
|
||||
const temperatureNull = !isSet(data?.temperature);
|
||||
const temperatureBlue = !temperatureNull && data?.temperature < TEMPERATURE_BLUE;
|
||||
const temperatureRed = !temperatureNull && data?.temperature > TEMPERATURE_RED;
|
||||
const temperatureGreen = !temperatureNull && !temperatureBlue && !temperatureRed;
|
||||
setClass(htmlTemperature.parentElement, "inputNull", temperatureNull);
|
||||
setClass(htmlTemperature.parentElement, "inputBlue", temperatureBlue);
|
||||
setClass(htmlTemperature.parentElement, "inputGreen", temperatureGreen);
|
||||
setClass(htmlTemperature.parentElement, "inputRed", temperatureRed);
|
||||
} catch (e) {
|
||||
reset(e);
|
||||
}
|
||||
}
|
||||
|
||||
function isSet(v) {
|
||||
return v !== null && v !== undefined;
|
||||
}
|
||||
|
||||
function reset(e) {
|
||||
console.error("Failed to handle data:", e);
|
||||
htmlTemperature.innerText = NO_VALUE;
|
||||
htmlRelative.innerText = NO_VALUE;
|
||||
htmlAbsolute.innerText = NO_VALUE;
|
||||
htmlIlluminance.innerText = NO_VALUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {HTMLElement} element
|
||||
* @param {string} className
|
||||
* @param {boolean} enabled
|
||||
*/
|
||||
function setClass(element, className, enabled) {
|
||||
if (element.classList.contains(className) !== enabled) {
|
||||
if (enabled) {
|
||||
element.classList.add(className);
|
||||
} else {
|
||||
element.classList.remove(className);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
status();
|
||||
setInterval(() => status(), 2000);
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@ -39,10 +39,10 @@ lib_deps = ${common.lib_deps}
|
||||
build_flags = ${common.build_flags} -DNODE_GREENHOUSE -DHOSTNAME=\"Greenhouse\"
|
||||
board_build.filesystem = ${common.board_build.filesystem}
|
||||
monitor_speed = ${common.monitor_speed}
|
||||
;upload_protocol = ${common.upload_protocol}
|
||||
;upload_port = 10.0.0.160
|
||||
upload_port = ${common.upload_port}
|
||||
upload_speed = ${common.upload_speed}
|
||||
upload_protocol = ${common.upload_protocol}
|
||||
upload_port = 10.0.0.160
|
||||
;upload_port = ${common.upload_port}
|
||||
;upload_speed = ${common.upload_speed}
|
||||
|
||||
[env:Fermenter]
|
||||
platform = ${esp12e.platform}
|
||||
@ -54,6 +54,6 @@ board_build.filesystem = ${common.board_build.filesystem}
|
||||
monitor_speed = ${common.monitor_speed}
|
||||
upload_flags = --auth=OtaAuthPatrixFermenter
|
||||
upload_protocol = ${common.upload_protocol}
|
||||
upload_port = 10.0.0.169
|
||||
upload_port = 10.0.0.164
|
||||
;upload_port = ${common.upload_port}
|
||||
;upload_speed = ${common.upload_speed}
|
||||
|
||||
@ -1,20 +0,0 @@
|
||||
#ifdef NODE_GREENHOUSE
|
||||
|
||||
#include "patrix/tsl2561.h"
|
||||
#include "patrix/bmp280_aht20.h"
|
||||
|
||||
TSL2561 greenhouse_TSL2561("greenhouse");
|
||||
|
||||
BMP280_AHT20 greenhouse_BMP280_AHT20("greenhouse");
|
||||
|
||||
void patrixSetup() {
|
||||
greenhouse_TSL2561.setup();
|
||||
greenhouse_BMP280_AHT20.setup();
|
||||
}
|
||||
|
||||
void patrixLoop() {
|
||||
greenhouse_TSL2561.loop();
|
||||
greenhouse_BMP280_AHT20.loop();
|
||||
}
|
||||
|
||||
#endif
|
||||
15
src/node/Greenhouse/Greenhouse.cpp
Normal file
15
src/node/Greenhouse/Greenhouse.cpp
Normal file
@ -0,0 +1,15 @@
|
||||
#ifdef NODE_GREENHOUSE
|
||||
|
||||
#include "http.h"
|
||||
#include "sensors.h"
|
||||
|
||||
void patrixSetup() {
|
||||
sensorsSetup();
|
||||
httpSetup2();
|
||||
}
|
||||
|
||||
void patrixLoop() {
|
||||
sensorsLoop();
|
||||
}
|
||||
|
||||
#endif
|
||||
25
src/node/Greenhouse/http.cpp
Normal file
25
src/node/Greenhouse/http.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
#ifdef NODE_GREENHOUSE
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#include "http.h"
|
||||
#include "sensors.h"
|
||||
#include "../../patrix/mqtt.h"
|
||||
|
||||
void httpStatus(AsyncWebServerRequest* request) {
|
||||
JsonDocument json;
|
||||
json["illuminance"] = greenhouseTSL.getIlluminance();;
|
||||
json["temperature"] = greenhouseDHT22.getTemperature();
|
||||
json["relative"] = greenhouseDHT22.getRelative();
|
||||
json["absolute"] = greenhouseDHT22.getAbsolute();
|
||||
|
||||
AsyncResponseStream* stream = request->beginResponseStream("application/json");
|
||||
serializeJson(json, *stream);
|
||||
request->send(stream);
|
||||
}
|
||||
|
||||
void httpSetup2() {
|
||||
server.on("/status", httpStatus);
|
||||
}
|
||||
|
||||
#endif
|
||||
16
src/node/Greenhouse/http.h
Normal file
16
src/node/Greenhouse/http.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifdef NODE_GREENHOUSE
|
||||
|
||||
#ifndef HTTP_H
|
||||
#define HTTP_H
|
||||
|
||||
#include "patrix/http.h"
|
||||
|
||||
void httpStatus(AsyncWebServerRequest* request);
|
||||
|
||||
void httpTargetAdd(AsyncWebServerRequest* request);
|
||||
|
||||
void httpSetup2();
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
19
src/node/Greenhouse/sensors.cpp
Normal file
19
src/node/Greenhouse/sensors.cpp
Normal file
@ -0,0 +1,19 @@
|
||||
#ifdef NODE_GREENHOUSE
|
||||
|
||||
#include "sensors.h"
|
||||
|
||||
TSL2561 greenhouseTSL("greenhouse");
|
||||
|
||||
DHT22Sensor greenhouseDHT22("greenhouse", D5);
|
||||
|
||||
void sensorsSetup() {
|
||||
greenhouseTSL.setup();
|
||||
greenhouseDHT22.setup();
|
||||
}
|
||||
|
||||
void sensorsLoop() {
|
||||
greenhouseTSL.loop();
|
||||
greenhouseDHT22.loop();
|
||||
}
|
||||
|
||||
#endif
|
||||
19
src/node/Greenhouse/sensors.h
Normal file
19
src/node/Greenhouse/sensors.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifdef NODE_GREENHOUSE
|
||||
|
||||
#ifndef SENSORS_H
|
||||
#define SENSORS_H
|
||||
|
||||
#include "patrix/DHT22.h"
|
||||
#include "patrix/tsl2561.h"
|
||||
|
||||
extern TSL2561 greenhouseTSL;
|
||||
|
||||
extern DHT22Sensor greenhouseDHT22;
|
||||
|
||||
void sensorsSetup();
|
||||
|
||||
void sensorsLoop();
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@ -1,8 +1,9 @@
|
||||
#ifndef DHT22_H
|
||||
#define DHT22_H
|
||||
|
||||
#include "mqtt.h"
|
||||
#include "DHT_U.h"
|
||||
#include "humidityRelative.h"
|
||||
#include "mqtt.h"
|
||||
|
||||
class DHT22Sensor {
|
||||
|
||||
@ -12,6 +13,12 @@ class DHT22Sensor {
|
||||
|
||||
unsigned long last = 0UL;
|
||||
|
||||
double temperature = NAN;
|
||||
|
||||
double relative = NAN;
|
||||
|
||||
double absolute = NAN;
|
||||
|
||||
public:
|
||||
|
||||
const String name;
|
||||
@ -24,30 +31,33 @@ public:
|
||||
|
||||
void setup() {
|
||||
dht.begin();
|
||||
last = millis();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
const auto now = max(1UL, millis());
|
||||
float temperature = NAN;
|
||||
if (last == 0 || now - last >= intervalMs) {
|
||||
if (now - last >= intervalMs) {
|
||||
sensors_event_t event;
|
||||
|
||||
dht.temperature().getEvent(&event);
|
||||
if (isnan(event.temperature)) {
|
||||
temperature = event.temperature;
|
||||
if (isnan(temperature)) {
|
||||
absolute = NAN;
|
||||
Log.error("Error reading temperature!");
|
||||
} else {
|
||||
temperature = event.temperature;
|
||||
mqttPublishValue(name + "/temperature", temperature, "TEMPERATURE_C");
|
||||
}
|
||||
|
||||
dht.humidity().getEvent(&event);
|
||||
if (isnan(event.relative_humidity)) {
|
||||
relative = event.relative_humidity;
|
||||
if (isnan(relative)) {
|
||||
absolute = NAN;
|
||||
Log.error("Error reading humidity!");
|
||||
} else {
|
||||
mqttPublishValue(name + "/humidity/relative", event.relative_humidity, "HUMIDITY_RELATIVE_PERCENT");
|
||||
mqttPublishValue(name + "/humidity/relative", relative, "HUMIDITY_RELATIVE_PERCENT");
|
||||
if (!isnan(temperature)) {
|
||||
double absHumid = calculateHumidityAbsolute(event.temperature, event.relative_humidity);
|
||||
mqttPublishValue(name + "/humidity/absolute", absHumid, "HUMIDITY_ABSOLUTE_GM3");
|
||||
absolute = calculateHumidityAbsolute(temperature, relative);
|
||||
mqttPublishValue(name + "/humidity/absolute", absolute, "HUMIDITY_ABSOLUTE_GM3");
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,16 +65,16 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
static double calculateHumidityAbsolute(const double temperature, const double humidityRelative) {
|
||||
constexpr auto A = 6.112;
|
||||
constexpr auto m = 17.67;
|
||||
constexpr auto Tn = 243.5;
|
||||
constexpr auto Mw = 18.01534;
|
||||
constexpr auto R = 8.314462618;
|
||||
const auto Tk = temperature + 273.15;
|
||||
const auto P_sat = A * exp((m * temperature) / (temperature + Tn));
|
||||
const auto P_act = P_sat * (humidityRelative / 100.0);
|
||||
return (P_act * Mw) / (R * Tk);
|
||||
[[nodiscard]] double getTemperature() const {
|
||||
return temperature;
|
||||
}
|
||||
|
||||
[[nodiscard]] double getRelative() const {
|
||||
return relative;
|
||||
}
|
||||
|
||||
[[nodiscard]] double getAbsolute() const {
|
||||
return absolute;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
#define BME680_H
|
||||
|
||||
#include "Adafruit_BME680.h"
|
||||
#include "humidityRelative.h"
|
||||
#include "mqtt.h"
|
||||
|
||||
class BME680 {
|
||||
@ -59,18 +60,6 @@ public:
|
||||
|
||||
}
|
||||
|
||||
static double calculateHumidityAbsolute(const double temperature, const double humidityRelative) {
|
||||
constexpr auto A = 6.112;
|
||||
constexpr auto m = 17.67;
|
||||
constexpr auto Tn = 243.5;
|
||||
constexpr auto Mw = 18.01534;
|
||||
constexpr auto R = 8.314462618;
|
||||
const auto Tk = temperature + 273.15;
|
||||
const auto P_sat = A * exp((m * temperature) / (temperature + Tn));
|
||||
const auto P_act = P_sat * (humidityRelative / 100.0);
|
||||
return (P_act * Mw) / (R * Tk);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
|
||||
#include "Adafruit_BMP280.h"
|
||||
#include "Adafruit_AHTX0.h"
|
||||
#include "humidityRelative.h"
|
||||
#include "mqtt.h"
|
||||
|
||||
class BMP280_AHT20 {
|
||||
@ -88,18 +89,6 @@ public:
|
||||
mqttPublishValue(name + "/absolute", absolute, "HUMIDITY_ABSOLUTE_GM3");
|
||||
}
|
||||
|
||||
static double calculateHumidityAbsolute(const double temperature, const double humidityRelative) {
|
||||
constexpr auto A = 6.112;
|
||||
constexpr auto m = 17.67;
|
||||
constexpr auto Tn = 243.5;
|
||||
constexpr auto Mw = 18.01534;
|
||||
constexpr auto R = 8.314462618;
|
||||
const auto Tk = temperature + 273.15;
|
||||
const auto P_sat = A * exp((m * temperature) / (temperature + Tn));
|
||||
const auto P_act = P_sat * (humidityRelative / 100.0);
|
||||
return (P_act * Mw) / (R * Tk);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
15
src/patrix/humidityRelative.cpp
Normal file
15
src/patrix/humidityRelative.cpp
Normal file
@ -0,0 +1,15 @@
|
||||
#include "humidityRelative.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
double calculateHumidityAbsolute(const double temperatureCelsius, const double humidityRelativePercent) {
|
||||
constexpr auto A = 6.112;
|
||||
constexpr auto m = 17.67;
|
||||
constexpr auto Tn = 243.5;
|
||||
constexpr auto Mw = 18.01534;
|
||||
constexpr auto R = 8.314462618;
|
||||
const auto Tk = temperatureCelsius + 273.15;
|
||||
const auto P_sat = A * exp((m * temperatureCelsius) / (temperatureCelsius + Tn));
|
||||
const auto P_act = P_sat * humidityRelativePercent;
|
||||
return (P_act * Mw) / (R * Tk);
|
||||
}
|
||||
6
src/patrix/humidityRelative.h
Normal file
6
src/patrix/humidityRelative.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef HUMIDITY_RELATIVE_H
|
||||
#define HUMIDITY_RELATIVE_H
|
||||
|
||||
double calculateHumidityAbsolute(double temperatureCelsius, double humidityRelativePercent);
|
||||
|
||||
#endif
|
||||
@ -10,6 +10,8 @@ class TSL2561 {
|
||||
|
||||
unsigned long last = 0UL;
|
||||
|
||||
int64_t illuminance = -1;
|
||||
|
||||
public:
|
||||
|
||||
const String name;
|
||||
@ -38,14 +40,19 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] int64_t getIlluminance() const {
|
||||
return illuminance;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void read() {
|
||||
uint16_t broadband;
|
||||
uint16_t ir;
|
||||
tsl.getLuminosity(&broadband, &ir);
|
||||
const auto illuminance = tsl.calculateLux(broadband, ir);
|
||||
illuminance = tsl.calculateLux(broadband, ir);
|
||||
if (illuminance == 65536) {
|
||||
illuminance = -1;
|
||||
Log.error("TSL2561 \"%s\": Failed to read.", name.c_str());
|
||||
setup();
|
||||
} else {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user