Compare commits

...

2 Commits

Author SHA1 Message Date
fa4e266bc5 Greenhouse: door, windows, light 2025-03-03 12:03:45 +01:00
1183be3d83 favicon 2025-03-03 11:34:13 +01:00
5 changed files with 149 additions and 16 deletions

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<polygon style="fill:#C8DB86;" points="503.83,172.381 435.647,172.381 283.648,59.589 351.831,59.589 "/>
<polygon style="fill:#D4ED85;" points="305.435,59.589 457.434,172.381 312.178,172.381 160.169,59.589 "/>
<rect x="249.54" y="172.381" style="fill:#FFE6B8;" width="62.638" height="280.031"/>
<rect x="8.17" y="172.381" style="fill:#FFF3DC;" width="263.157" height="280.031"/>
<rect x="104.001" y="172.381" style="fill:#D4ED85;" width="112.357" height="280.042"/>
<rect x="430.298" y="172.381" style="fill:#BCC987;" width="73.532" height="280.031"/>
<rect x="312.178" y="172.381" style="fill:#C8DB86;" width="150.8" height="280.031"/>
<polygon style="fill:#FFF3DC;" points="312.178,172.381 136.976,172.381 136.976,76.801 160.169,59.589 "/>
<polygon style="fill:#FFFFFF;" points="265.782,172.381 8.17,172.381 136.976,76.801 "/>
<path style="fill:#9CAC74;" d="M208.178,172.377v85.176h-96.011v-85.176h-16.34v85.176h-2.723c-4.512,0-8.17,3.657-8.17,8.17c0,4.513,3.658,8.17,8.17,8.17h2.723v77.005h-2.723c-4.512,0-8.17,3.657-8.17,8.17s3.658,8.17,8.17,8.17h2.723v85.176h16.34v-85.176h96.011v85.176h16.34V172.377H208.178z M112.167,350.899v-77.005h96.011v77.005H112.167z"/>
<path style="fill:#7D9062;" d="M183.667,332.34c-4.512,0-8.17-3.657-8.17-8.17v-23.545c0-4.513,3.658-8.17,8.17-8.17s8.17,3.657,8.17,8.17v23.545C191.838,328.683,188.18,332.34,183.667,332.34z"/>
<path style="fill:#7D9062;" d="M508.698,165.817L356.696,53.024c-1.409-1.046-3.116-1.61-4.869-1.61H160.173c-1.754,0-3.461,0.564-4.868,1.61L3.302,165.817C1.224,167.357,0,169.791,0,172.377v280.039c0,4.513,3.658,8.17,8.17,8.17h495.66c4.513,0,8.17-3.657,8.17-8.17V172.377C512,169.791,510.776,167.357,508.698,165.817z M253.301,67.754l129.98,96.452h-68.405L184.893,67.754C184.893,67.754,253.301,67.754,253.301,67.754z M160.173,69.758l127.282,94.449H32.892L160.173,69.758zM16.34,180.547h287.664v263.698H16.34V180.547z M399.832,444.247h-79.486v-263.7h79.486V444.247z M280.721,67.754h68.405l129.982,96.452h-68.406L280.721,67.754z M495.66,444.247h-79.487v-263.7h79.487V444.247z"/>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -3,11 +3,12 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.svg">
<title>Gewächshaus</title> <title>Gewächshaus</title>
<style> <style>
body { body {
font-family: sans-serif; font-family: sans-serif;
font-size: 12vw; font-size: 8vw;
margin: 0; margin: 0;
-webkit-user-select: none; -webkit-user-select: none;
-ms-user-select: none; -ms-user-select: none;
@ -49,6 +50,11 @@
float: left; float: left;
} }
img {
height: 1.5em;
vertical-align: middle;
}
.unit { .unit {
float: left; float: left;
margin-left: 0.25em; margin-left: 0.25em;
@ -63,11 +69,11 @@
color: blue; color: blue;
} }
.inputGreen { .inputGreen, #lightOn {
color: #00ff00; color: #00ff00;
} }
.inputRed { .inputRed, #lightOff {
color: #ba0000; color: #ba0000;
} }
@ -110,26 +116,60 @@
</div> </div>
</div> </div>
<div class="section">
<div class="title">Tür</div>
<div class="valueAndUnit">
<div class="value" id="door"></div>
</div>
</div>
<div class="section">
<div class="title">Fenster</div>
<div class="valueAndUnit">
<div class="value" id="windows"></div>
</div>
</div>
<div class="section">
<div class="title">Licht</div>
<div class="valueAndUnit">
<span id="lightUnknown">?</span>
<div id="lightOn">
Ein
<img alt="Ein" src="on.svg" onclick="get('/light/off')">
</div>
<div id="lightOff">
Aus
<img alt="Aus" src="off.svg" onclick="get('/light/on')">
</div>
</div>
</div>
</div> </div>
<script> <script>
const NO_VALUE = "- - -"; const NO_VALUE = "?";
const TEMPERATURE_BLUE = 10; const TEMPERATURE_BLUE = 10;
const TEMPERATURE_RED = 35; const TEMPERATURE_RED = 35;
const RELATIVE_BLUE = 60; const RELATIVE_BLUE = 60;
const RELATIVE_RED = 80; const RELATIVE_RED = 80;
const htmlTemperature = document.getElementById('temperature'); const htmlTemperature = document.getElementById('temperature');
const htmlRelative = document.getElementById('relative'); const htmlRelative = document.getElementById('relative');
const htmlAbsolute = document.getElementById('absolute'); const htmlAbsolute = document.getElementById('absolute');
const htmlIlluminance = document.getElementById('illuminance'); const htmlIlluminance = document.getElementById('illuminance');
const htmlDoor = document.getElementById('door');
const htmlWindows = document.getElementById('windows');
const htmlLightOn = document.getElementById('lightOn');
const htmlLightOff = document.getElementById('lightOff');
const htmlLightUnknown = document.getElementById('lightUnknown');
function status() { function status() {
get("/status"); get("/status");
} }
function get(path) { function get(path) {
const request = new XMLHttpRequest(); const request = new XMLHttpRequest();
request.onreadystatechange = function () { request.onreadystatechange = function () {
@ -140,11 +180,11 @@
request.open('GET', (location.hostname === "localhost" ? "http://10.0.0.160" : "") + path); request.open('GET', (location.hostname === "localhost" ? "http://10.0.0.160" : "") + path);
request.send(); request.send();
} }
function format(value, decimals) { function format(value, decimals) {
return value?.toLocaleString(undefined, {minimumFractionDigits: decimals, maximumFractionDigits: decimals}); return value?.toLocaleString(undefined, {minimumFractionDigits: decimals, maximumFractionDigits: decimals});
} }
function update(response) { function update(response) {
try { try {
const data = JSON.parse(response); const data = JSON.parse(response);
@ -152,7 +192,23 @@
htmlRelative.innerText = format(data?.relative, 0) || NO_VALUE; htmlRelative.innerText = format(data?.relative, 0) || NO_VALUE;
htmlAbsolute.innerText = format(data?.absolute, 1) || NO_VALUE; htmlAbsolute.innerText = format(data?.absolute, 1) || NO_VALUE;
htmlIlluminance.innerText = format(data?.illuminance, 0) || NO_VALUE; htmlIlluminance.innerText = format(data?.illuminance, 0) || NO_VALUE;
const doorClosed = data?.door === true;
const doorOpened = data?.door === false;
htmlDoor.innerText = doorClosed ? 'Geschlosssen' : doorOpened ? 'Offen' : NO_VALUE;
setClass(htmlDoor.parentElement, "inputRed", doorOpened);
setClass(htmlDoor.parentElement, "inputGreen", doorClosed);
const windowsClosed = data?.windows === true;
const windowsOpened = data?.windows === false;
htmlWindows.innerText = windowsClosed ? 'Geschlosssen' : windowsOpened ? 'Offen' : NO_VALUE;
setClass(htmlWindows.parentElement, "inputRed", windowsOpened);
setClass(htmlWindows.parentElement, "inputGreen", windowsClosed);
htmlLightOn.style.display = data?.light === true ? 'block' : 'none';
htmlLightOff.style.display = data?.light === false ? 'block' : 'none';
htmlLightUnknown.style.display = data?.light !== false && data?.light !== true ? 'block' : 'none';
const relativeNull = !isSet(data?.relative); const relativeNull = !isSet(data?.relative);
const relativeBlue = !relativeNull && data?.relative < RELATIVE_BLUE; const relativeBlue = !relativeNull && data?.relative < RELATIVE_BLUE;
const relativeRed = !relativeNull && data?.relative > RELATIVE_RED; const relativeRed = !relativeNull && data?.relative > RELATIVE_RED;
@ -174,19 +230,24 @@
reset(e); reset(e);
} }
} }
function isSet(v) { function isSet(v) {
return v !== null && v !== undefined; return v !== null && v !== undefined;
} }
function reset(e) { function reset(e) {
console.error("Failed to handle data:", e); console.error("Failed to handle data:", e);
htmlTemperature.innerText = NO_VALUE; htmlTemperature.innerText = NO_VALUE;
htmlRelative.innerText = NO_VALUE; htmlRelative.innerText = NO_VALUE;
htmlAbsolute.innerText = NO_VALUE; htmlAbsolute.innerText = NO_VALUE;
htmlIlluminance.innerText = NO_VALUE; htmlIlluminance.innerText = NO_VALUE;
htmlDoor.innerText = NO_VALUE;
htmlWindows.innerText = NO_VALUE;
htmlLightOn.style.display = 'none';
htmlLightOff.style.display = 'none';
htmlLightUnknown.style.display = 'block';
} }
/** /**
* @param {HTMLElement} element * @param {HTMLElement} element
* @param {string} className * @param {string} className
@ -201,7 +262,7 @@
} }
} }
} }
status(); status();
setInterval(() => status(), 2000); setInterval(() => status(), 2000);

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="800px" height="800px" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<g transform="translate(0 -1028.4)">
<path d="m7 1034.4c-3.3137 0-6 2.6-6 6 0 3.3 2.6863 6 6 6h5 5c3.314 0 6-2.7 6-6 0-3.4-2.686-6-6-6h-5-5z" fill="#95a5a6"/>
<path d="m7 1033.4c-3.3137 0-6 2.6-6 6 0 3.3 2.6863 6 6 6h5 5c3.314 0 6-2.7 6-6 0-3.4-2.686-6-6-6h-5-5z" fill="#bdc3c7"/>
<path d="m7 1035.4c-2.2091 0-4 1.8-4 4s1.7909 4 4 4h5 5c2.209 0 4-1.8 4-4s-1.791-4-4-4h-5-5z" fill="#e74c3c"/>
<path d="m7 1035.4c-2.2091 0-4 1.8-4 4 0 0.1 0.0419 0.3 0.0625 0.5 0.2471-2 1.8985-3.5 3.9375-3.5h5 5c2.039 0 3.69 1.5 3.938 3.5 0.02-0.2 0.062-0.4 0.062-0.5 0-2.2-1.791-4-4-4h-5-5z" fill="#c0392b"/>
<g transform="translate(-11.5,-11.4)">
<g transform="translate(10.5,10.4)">
<path d="m13.023 1039.7-0.023 1.2c-0.04 1.9 1.567 3.5 3.5 3.5h1.5c2.209 0 4-1.8 4-4 0-0.4-0.074-0.7-0.156-1z" fill="#7f8c8d"/>
<path d="m16.5 1036.4c-1.933 0-3.5 1.5-3.5 3.5 0 1.9 1.567 3.5 3.5 3.5h2c1.933 0 3.5-1.6 3.5-3.5 0-2-1.567-3.5-3.5-3.5h-2z" fill="#ecf0f1"/>
<g fill="#bdc3c7">
<path d="m15.5 1037.4c-0.276 0-0.5 0.1-0.5 0.4v3.2c0 0.2 0.224 0.4 0.5 0.4s0.5-0.2 0.5-0.4v-3.2c0-0.3-0.224-0.4-0.5-0.4z"/>
<path d="m17.5 1037.4c-0.276 0-0.5 0.1-0.5 0.4v3.2c0 0.2 0.224 0.4 0.5 0.4s0.5-0.2 0.5-0.4v-3.2c0-0.3-0.224-0.4-0.5-0.4z"/>
<path d="m19.5 1037.4c-0.276 0-0.5 0.1-0.5 0.4v3.2c0 0.2 0.224 0.4 0.5 0.4s0.5-0.2 0.5-0.4v-3.2c0-0.3-0.224-0.4-0.5-0.4z"/>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<g transform="translate(0 -1028.4)">
<path d="m17 1034.4c3.314 0 6 2.6 6 6 0 3.3-2.686 6-6 6h-5-5c-3.3137 0-6-2.7-6-6 0-3.4 2.6863-6 6-6h5 5z" fill="#95a5a6"/>
<path d="m17 1033.4c3.314 0 6 2.6 6 6 0 3.3-2.686 6-6 6h-5-5c-3.3137 0-6-2.7-6-6 0-3.4 2.6863-6 6-6h5 5z" fill="#bdc3c7"/>
<path d="m17 1035.4c2.209 0 4 1.8 4 4s-1.791 4-4 4h-5-5c-2.2091 0-4-1.8-4-4s1.7909-4 4-4h5 5z" fill="#2ecc71"/>
<path d="m17 1035.4c2.209 0 4 1.8 4 4 0 0.1-0.042 0.3-0.062 0.5-0.248-2-1.899-3.5-3.938-3.5h-5-5c-2.039 0-3.6904 1.5-3.9375 3.5-0.0206-0.2-0.0625-0.4-0.0625-0.5 0-2.2 1.7909-4 4-4h5 5z" fill="#27ae60"/>
<g transform="matrix(-1,0,0,1,35.5,-11.4)">
<g transform="translate(10.5,10.4)">
<path d="m13.023 1039.7-0.023 1.2c-0.04 1.9 1.567 3.5 3.5 3.5h1.5c2.209 0 4-1.8 4-4 0-0.4-0.074-0.7-0.156-1z" fill="#7f8c8d"/>
<path d="m16.5 1036.4c-1.933 0-3.5 1.5-3.5 3.5 0 1.9 1.567 3.5 3.5 3.5h2c1.933 0 3.5-1.6 3.5-3.5 0-2-1.567-3.5-3.5-3.5h-2z" fill="#ecf0f1"/>
<g fill="#bdc3c7">
<path d="m15.5 1037.4c-0.276 0-0.5 0.1-0.5 0.4v3.2c0 0.2 0.224 0.4 0.5 0.4s0.5-0.2 0.5-0.4v-3.2c0-0.3-0.224-0.4-0.5-0.4z"/>
<path d="m17.5 1037.4c-0.276 0-0.5 0.1-0.5 0.4v3.2c0 0.2 0.224 0.4 0.5 0.4s0.5-0.2 0.5-0.4v-3.2c0-0.3-0.224-0.4-0.5-0.4z"/>
<path d="m19.5 1037.4c-0.276 0-0.5 0.1-0.5 0.4v3.2c0 0.2 0.224 0.4 0.5 0.4s0.5-0.2 0.5-0.4v-3.2c0-0.3-0.224-0.4-0.5-0.4z"/>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -6,20 +6,37 @@
#include "sensors.h" #include "sensors.h"
#include "../../patrix/mqtt.h" #include "../../patrix/mqtt.h"
bool light = false;
void httpStatus(AsyncWebServerRequest* request) { void httpStatus(AsyncWebServerRequest* request) {
JsonDocument json; JsonDocument json;
json["illuminance"] = greenhouseTSL.getIlluminance();; json["illuminance"] = greenhouseTSL.getIlluminance();;
json["temperature"] = greenhouseDHT22.getTemperature(); json["temperature"] = greenhouseDHT22.getTemperature();
json["relative"] = greenhouseDHT22.getRelative(); json["relative"] = greenhouseDHT22.getRelative();
json["absolute"] = greenhouseDHT22.getAbsolute(); json["absolute"] = greenhouseDHT22.getAbsolute();
json["door"] = false;
json["windows"] = false;
json["light"] = light;
AsyncResponseStream* stream = request->beginResponseStream("application/json"); AsyncResponseStream* stream = request->beginResponseStream("application/json");
serializeJson(json, *stream); serializeJson(json, *stream);
request->send(stream); request->send(stream);
} }
void httpLightOn(AsyncWebServerRequest* request) {
light = true;
httpStatus(request);
}
void httpLightOff(AsyncWebServerRequest* request) {
light = false;
httpStatus(request);
}
void httpSetup2() { void httpSetup2() {
server.on("/status", httpStatus); server.on("/status", httpStatus);
server.on("/light/on", httpLightOn);
server.on("/light/off", httpLightOff);
} }
#endif #endif