Esp8266 Windsensor TX23 als Arduino Tab.
TX23.ino
// ****************************************************************
// Sketch Esp8266 TX23 Windgeschwindigkeit- und Richtung Modular(Tab)
// Include FIFO Puffer for Hour, Day, Week
// created: Jens Fleischer, 2019-12-09
// last mod: Jens Fleischer, 2020-11-12
// For more information visit: https://fipsok.de
// ****************************************************************
// Hardware: Esp8266, TX23
// Braun (Schwarz) DATA an D5 = GPIO14
// Red an Vcc
// Grün --
// Gelb an GND
// Software: Esp8266 Arduino Core 2.4.2 / 2.5.2 / 2.6.3 / 2.7.4
// Getestet auf: Nodemcu
/******************************************************************
Copyright (c) 2019 Jens Fleischer. All rights reserved.
This file is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This file is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
*******************************************************************/
// Diese Version vom Windsensor sollte als Tab eingebunden werden.
// #include <WebServer.h> muss im Haupttab aufgerufen werden
// Die Funktionalität des ESP8266 Webservers ist erforderlich.
// Die Funktion "tx23();" muss im Setup aufgerufen werden.
// Die Funktion "tx23Read();" muss zum füllen der Fifo Puffer im loop(); aufgerufen werden.
/**************************************************************************************/
#include <LaCrosse_TX23.h> // https://github.com/egzumer/Arduino-LaCrosse-TX23-Library
LaCrosse_TX23 anemometer = LaCrosse_TX23(D5); // Pin anpassen
float fifoHour[60], fifoMaxHour[60], fifoDay[24], fifoMaxDay[24], fifoWeek[7], fifoMaxWeek[7]; // Fifo Puffer
template<typename T, size_t count>
T maxRead(const T (&arr)[count]) { // max Wert aus Array ermitteln
T maxValue {arr[0]};
for (const auto &value : arr) maxValue = max(maxValue, value);
return maxValue;
}
template<typename T, size_t count>
T averageRead(const T (&arr)[count]) { // Durchschnitt aus Array berechnen
double average {0};
for (const auto &value : arr) average += static_cast<double>(value) / count;
return std::numeric_limits<T>::is_integer ? round(average) : average;
}
template<typename T, size_t count> // Array Größe zur Kompilezeit ermitteln
constexpr size_t arrayCount(const T (&)[count]) {
return count;
}
constexpr byte hourSize = arrayCount(fifoHour);
constexpr byte daySize = arrayCount(fifoDay);
constexpr byte weekSize = arrayCount(fifoWeek);
void tx23() { // Funktionsaufruf "tx23();" muss im Setup eingebunden werden
server.on("/tx23", []() {
server.send(200, "application/json", tx23Read());
});
}
const char* tx23Read() { // Funktionsaufruf "tx23Read();" muss im Loop eingebunden werden
static char buf[63];
static bool correct;
static float maxSpeed, speedValue, speed;
static uint8_t numberOfValue, indexHour, indexDay, indexWeek; // Index Fifo Puffer
static int32_t direction;
static uint32_t previousMillis[2];
uint32_t currentMillis {millis()};
if (currentMillis - previousMillis[0] >= 3e3) { // aller 3 Sekunden
previousMillis[0] = currentMillis;
if ((correct = anemometer.read(speed, direction)) && speed < 52) { // Sensor auslesen
maxSpeed = max(maxSpeed, speed); // max Wert ermitteln
speedValue += speed;
numberOfValue++;
}
}
if (currentMillis - previousMillis[1] >= 6e4) { // jede Minute
previousMillis[1] = currentMillis;
fifoHour[indexHour] = speedValue / numberOfValue; // 60 Minuten Puffer Durchschnitt übergeben
fifoMaxHour[indexHour] = maxSpeed; // 60 Minuten Puffer max Wert übergeben
++indexHour, indexHour %= (hourSize); // 60 Minuten Puffer Zeiger im Puffer vorrücken
maxSpeed = 0; // maxSpeed zurücksetzen
speedValue = 0; // Durchschnitt zurücksetzen
numberOfValue = 0; // Zähler zurücksetzen
if (indexHour == 0) {
++indexDay, indexDay %= (daySize); // 24 Stunden Puffer Zeiger im Puffer vorrücken
}
fifoDay[indexDay] = averageRead(fifoHour); // 24 Stunden Puffer Durchschnitt übergeben
fifoMaxDay[indexDay] = maxRead(fifoMaxHour); // 24 Stunden Puffer max Wert übergeben
if (indexHour == 0 && indexDay == 0) {
static byte fill {0}; // In der ersten Woche das Array auffüllen
if (fill < weekSize) for (byte i = fill++; i < weekSize; i++)fifoWeek[i] = averageRead(fifoDay);
++indexWeek, indexWeek %= weekSize; // 7 Tage Puffer Zeiger im Puffer vorrücken
}
fifoWeek[indexWeek] = averageRead(fifoDay); // 7 Tage Puffer Durchschnitt übergeben
fifoMaxWeek[indexWeek] = maxRead(fifoMaxDay); // 7 Tage Puffer max Wert übergeben
}
snprintf(buf, sizeof(buf), R"(["%d","%.1f","%.1f","%.1f","%.1f","%.1f","%.1f","%.1f"])",
direction, speed, averageRead(fifoHour), maxRead(fifoMaxHour), averageRead(fifoDay), maxRead(fifoMaxDay), averageRead(fifoWeek), maxRead(fifoMaxWeek));
return correct ? buf : "[\"nan\"]";
}
Die Webseite zum Esp8266 TX23 Windsensor.
tx23.html
<!DOCTYPE HTML> <!-- For more information visit: https://fipsok.de -->
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="style.css">
<title>Anemometer</title>
<script>
direction = ['m96.37 19 3.625-6.052 3.625 6.052-3.625 19.33z',
'm127.6 23.78 5.665-4.204 1.033 6.978-10.75 16.47z',
'm154.7 40.16 6.842-1.716-1.716 6.842-16.23 11.11z',
'm173.4 65.65 6.978 1.033-4.204 5.665-19.25 4.049z',
'm181 96.36 6.052 3.625-6.052 3.625-19.33-3.625z',
'm176.2 127.6 4.204 5.665-6.978 1.033-16.47-10.75z',
'm159.8 154.7 1.716 6.842-6.842-1.716-11.11-16.23z',
'm134.3 173.4-1.033 6.978-5.665-4.204-4.049-19.25z',
'm103.6 181-3.625 6.052-3.625-6.052 3.625-19.33z',
'm72.34 176.2-5.665 4.204-1.033-6.978 10.75-16.47z',
'm45.29 159.8-6.842 1.716 1.716-6.842 16.23-11.11z',
'm26.56 134.3-6.978-1.033 4.204-5.665 19.25-4.049z',
'm19.01 103.6-6.052-3.625 6.052-3.625 19.33 3.625z',
'm23.79 72.33-4.204-5.665 6.978-1.033 16.47 10.75z',
'm40.17 45.28-1.716-6.842 6.842 1.716 11.11 16.23z',
'm65.66 26.55 1.033-6.978 5.665 4.204 4.049 19.25z'];
function renew() {
fetch('tx23').then(function (response) {
return response.json();
}).then(function (array) {
var elem = document.querySelectorAll('b');
if (array[0] != 'nan') {
document.getElementById('arrow').setAttribute("d", direction[array[0]]);
elem[0].innerHTML = array[1];
elem[1].innerHTML = array[2];
elem[2].innerHTML = array[3];
elem[3].innerHTML = array[1];
elem[4].innerHTML = array[6];
elem[5].innerHTML = array[7];
elem[6].innerHTML = array[1];
elem[7].innerHTML = array[4];
elem[8].innerHTML = array[5];
}
else {
elem[1].innerHTML = '----';
elem[3].innerHTML = '----';
elem[6].innerHTML = '----';
}
});
}
document.addEventListener('DOMContentLoaded', renew);
setInterval(renew, 2000);
</script>
<style>
svg {
height: 22em;
z-index: 9;
pointer-events: none;
}
main {
display: flex;
flex-direction: column;
align-items: center;
position: absolute;
top: 4em;
font-size: 1.5em;
font-weight: bold;
}
span {
display: block;
}
b {
font-size: 1.5em;
}
label {
position: absolute;
width: 9em;
padding: 4em 2.5em;
background-color: #87cefa;
text-align: center;
user-select: none;
}
:checked + label {
z-index: 8;
pointer-events: none;
}
:checked + label + input + label {
pointer-events: none;
}
</style>
</head>
<body>
<h1>Windsensor</h1>
<svg viewBox="0 0 200 200">
<g font-family="Arial Rounded MT Bold" font-size="9.5px">
<path d="m175.4 73.296c2.5652 7.2385 4.0786 14.849 4.4791 22.518m-20.446-49.341c5.14 5.7058 9.4505 12.157 12.755 19.09m-37.771-37.76c6.9323 3.3045 13.384 7.6155 19.09 12.755m-49.346-20.431c7.6692 0.40007 15.279 1.9141 22.518 4.479m-53.409 8e-3c7.2385-2.5652 14.849-4.0787 22.518-4.4791m-49.34 20.446c5.7058-5.14 12.157-9.4505 19.09-12.755m-37.76 37.771c3.3045-6.9323 7.6155-13.384 12.755-19.09m-20.431 49.346c0.40007-7.6692 1.9141-15.279 4.479-22.518m0.0078 53.408c-2.5652-7.2385-4.0787-14.849-4.4791-22.518m20.446 49.34c-5.14-5.7058-9.4505-12.157-12.755-19.09m37.771 37.76c-6.9323-3.3045-13.384-7.6155-19.09-12.755m49.346 20.43c-7.6692-0.40007-15.279-1.9141-22.518-4.479m53.409-8e-3c-7.2385 2.5652-14.849 4.0786-22.518 4.479m68.011-45.462c-3.3045 6.9323-7.6155 13.384-12.755 19.09m-5.9154 5.9264c-5.7058 5.14-12.157 9.4505-19.09 12.755m45.436-68.027c-0.40002 7.6692-1.9144 15.28-4.479 22.518" stroke="#666" stroke-width="3" />
<path id="arrow" d="" />
<text x="96" y="11">N</text>
<text x="162" y="38">NO</text>
<text x="161" y="169">SO</text>
<text x="97" y="196">S</text>
<text x="23" y="169">SW</text>
<text x="3" y="102">W</text>
<text x="23" y="38">NW</text>
<text x="188" y="103">O</text>
</g>
</svg>
<main>
<input id="hour" type="radio" name="set" checked="checked">
<label for="hour">
<span>
<b>
</b>
m/s
</span>
<span>
<b>
</b>
⌀ hour
</span>
<span>
<b>
</b>
max/h
</span>
</label>
<input id="week" type="radio" name="set">
<label for="week">
<span>
<b>
</b>
m/s
</span>
<span>
<b>
</b>
⌀ week
</span>
<span>
<b>
</b>
max/w
</span>
</label>
<input id="day" type="radio" name="set">
<label for="day">
<span>
<b>
</b>
m/s
</span>
<span>
<b>
</b>
⌀ day
</span>
<span>
<b>
</b>
max/d
</span>
</label>
</main>
</body>
</html>