Fermenter + Log.debug/info/warn/error + removed yield() from mqtt + String name FIX
This commit is contained in:
parent
e4a27808c0
commit
674fafc318
194
data/http/index.html
Normal file
194
data/http/index.html
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="de">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>Gärbox</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: sans-serif;
|
||||||
|
font-size: 16vw;
|
||||||
|
margin: 0.1em;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
div {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section {
|
||||||
|
clear: both;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 50%;
|
||||||
|
font-style: italic;
|
||||||
|
text-align: center;
|
||||||
|
color: gray
|
||||||
|
}
|
||||||
|
|
||||||
|
.valueAndUnit {
|
||||||
|
clear: both;
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.controlPadding {
|
||||||
|
float: left;
|
||||||
|
padding: 0 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.value {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.unit {
|
||||||
|
float: left;
|
||||||
|
width: 1.2em;
|
||||||
|
margin-left: 0.25em;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
float: left;
|
||||||
|
width: 1em;
|
||||||
|
margin-top: 0.2em;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inputNull {
|
||||||
|
color: gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inputCold {
|
||||||
|
color: blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inputGood {
|
||||||
|
color: green;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inputWarm {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<div class="title">Ist-Temperatur</div>
|
||||||
|
<div class="valueAndUnit">
|
||||||
|
<div class="value" id="input"></div>
|
||||||
|
<div class="unit">°C</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<div class="title">Ziel-Temperatur</div>
|
||||||
|
<div class="valueAndUnit">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="blue" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" onclick="targetAdd(-0.5)">
|
||||||
|
<path d="M7 12H17"/>
|
||||||
|
<circle cx="12" cy="12" r="10"/>
|
||||||
|
</svg>
|
||||||
|
<div class="controlPadding">
|
||||||
|
<div class="value" id="target"></div>
|
||||||
|
<div class="unit">°C</div>
|
||||||
|
</div>
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="red" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" onclick="targetAdd(+0.5)">
|
||||||
|
<path d="M12 7V17M7 12H17"/>
|
||||||
|
<circle cx="12" cy="12" r="10"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<div class="title">Heizung</div>
|
||||||
|
<div class="valueAndUnit">
|
||||||
|
<div class="value" id="outputPercent"></div>
|
||||||
|
<div class="unit">%</div>
|
||||||
|
</div>
|
||||||
|
<div class="valueAndUnit">
|
||||||
|
<div class="value" id="outputPowerW"></div>
|
||||||
|
<div class="unit">W</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
const input = document.getElementById('input');
|
||||||
|
const target = document.getElementById('target');
|
||||||
|
const outputPercent = document.getElementById('outputPercent');
|
||||||
|
const outputPowerW = document.getElementById('outputPowerW');
|
||||||
|
|
||||||
|
function status() {
|
||||||
|
get("/status");
|
||||||
|
}
|
||||||
|
|
||||||
|
function targetAdd(delta) {
|
||||||
|
get("/target/add?delta=" + delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
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.171" : "") + path);
|
||||||
|
request.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
function update(response) {
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(response);
|
||||||
|
if (data === null || data === undefined || !data.hasOwnProperty("target") || !data.hasOwnProperty("input") || !data.hasOwnProperty("outputPercent") || !data.hasOwnProperty("outputPowerW")) {
|
||||||
|
throw new Error("Invalid data");
|
||||||
|
}
|
||||||
|
input.innerText = data.input == null ? "- - -" : data.input.toFixed(1);
|
||||||
|
target.innerText = data.target.toFixed(1);
|
||||||
|
outputPercent.innerText = data.outputPercent.toFixed(0);
|
||||||
|
outputPowerW.innerText = data.outputPowerW.toFixed(0);
|
||||||
|
const inputNull = data.input === null;
|
||||||
|
const inputCold = !inputNull && data.input < data.target - 0.5;
|
||||||
|
const inputWarm = !inputNull && data.input > data.target + 0.5;
|
||||||
|
const inputGood = !inputNull && !inputCold && !inputWarm;
|
||||||
|
setClass(input.parentElement, "inputNull", inputNull);
|
||||||
|
setClass(input.parentElement, "inputCold", inputCold);
|
||||||
|
setClass(input.parentElement, "inputGood", inputGood);
|
||||||
|
setClass(input.parentElement, "inputWarm", inputWarm);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to handle data:", e);
|
||||||
|
input.innerText = "- - -";
|
||||||
|
target.innerText = "- - -";
|
||||||
|
outputPercent.innerText = "- - -";
|
||||||
|
outputPowerW.innerText = "- - -";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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>
|
||||||
@ -4,10 +4,15 @@ lib_deps = https://github.com/milesburton/Arduino-Temperature-Control-Library
|
|||||||
https://github.com/adafruit/Adafruit_TSL2561
|
https://github.com/adafruit/Adafruit_TSL2561
|
||||||
https://github.com/knolleary/pubsubclient
|
https://github.com/knolleary/pubsubclient
|
||||||
https://github.com/adafruit/Adafruit_BME680
|
https://github.com/adafruit/Adafruit_BME680
|
||||||
|
https://github.com/phassel/ArduPID/
|
||||||
|
https://github.com/me-no-dev/ESPAsyncWebServer
|
||||||
|
https://github.com/wayoda/LedControl
|
||||||
build_flags =
|
build_flags =
|
||||||
|
board_build.filesystem = littlefs
|
||||||
monitor_speed = 115200
|
monitor_speed = 115200
|
||||||
;upload_port = /dev/ttyUSB0
|
upload_port = /dev/ttyUSB0
|
||||||
;upload_speed = 460800
|
upload_speed = 460800
|
||||||
|
upload_protocol = espota
|
||||||
|
|
||||||
[esp12e]
|
[esp12e]
|
||||||
platform = espressif8266
|
platform = espressif8266
|
||||||
@ -23,9 +28,10 @@ board = ${esp12e.board}
|
|||||||
framework = ${common.framework}
|
framework = ${common.framework}
|
||||||
lib_deps = ${common.lib_deps}
|
lib_deps = ${common.lib_deps}
|
||||||
build_flags = ${common.build_flags} -DNODE_GREENHOUSE -DHOSTNAME=\"Greenhouse\"
|
build_flags = ${common.build_flags} -DNODE_GREENHOUSE -DHOSTNAME=\"Greenhouse\"
|
||||||
|
board_build.filesystem = ${common.board_build.filesystem}
|
||||||
monitor_speed = ${common.monitor_speed}
|
monitor_speed = ${common.monitor_speed}
|
||||||
upload_port = /dev/ttyUSB0
|
upload_port = ${common.upload_port}
|
||||||
upload_speed = 460800
|
upload_speed = ${common.upload_speed}
|
||||||
|
|
||||||
[env:GreenhouseOTA]
|
[env:GreenhouseOTA]
|
||||||
platform = ${esp12e.platform}
|
platform = ${esp12e.platform}
|
||||||
@ -33,9 +39,10 @@ board = ${esp12e.board}
|
|||||||
framework = ${common.framework}
|
framework = ${common.framework}
|
||||||
lib_deps = ${common.lib_deps}
|
lib_deps = ${common.lib_deps}
|
||||||
build_flags = ${common.build_flags} -DNODE_GREENHOUSE -DHOSTNAME=\"Greenhouse\"
|
build_flags = ${common.build_flags} -DNODE_GREENHOUSE -DHOSTNAME=\"Greenhouse\"
|
||||||
|
board_build.filesystem = ${common.board_build.filesystem}
|
||||||
monitor_speed = ${common.monitor_speed}
|
monitor_speed = ${common.monitor_speed}
|
||||||
upload_protocol = espota
|
upload_protocol = ${common.upload_protocol}
|
||||||
upload_port = 10.0.0.169
|
upload_port = 10.0.0.160
|
||||||
|
|
||||||
[env:FermenterUSB]
|
[env:FermenterUSB]
|
||||||
platform = ${esp12e.platform}
|
platform = ${esp12e.platform}
|
||||||
@ -43,9 +50,10 @@ board = ${esp12e.board}
|
|||||||
framework = ${common.framework}
|
framework = ${common.framework}
|
||||||
lib_deps = ${common.lib_deps}
|
lib_deps = ${common.lib_deps}
|
||||||
build_flags = ${common.build_flags} -DNODE_FERMENTER -DHOSTNAME=\"Fermenter\"
|
build_flags = ${common.build_flags} -DNODE_FERMENTER -DHOSTNAME=\"Fermenter\"
|
||||||
|
board_build.filesystem = ${common.board_build.filesystem}
|
||||||
monitor_speed = ${common.monitor_speed}
|
monitor_speed = ${common.monitor_speed}
|
||||||
upload_port = /dev/ttyUSB0
|
upload_port = ${common.upload_port}
|
||||||
upload_speed = 460800
|
upload_speed = ${common.upload_speed}
|
||||||
|
|
||||||
[env:FermenterOTA]
|
[env:FermenterOTA]
|
||||||
platform = ${esp12e.platform}
|
platform = ${esp12e.platform}
|
||||||
@ -53,6 +61,8 @@ board = ${esp12e.board}
|
|||||||
framework = ${common.framework}
|
framework = ${common.framework}
|
||||||
lib_deps = ${common.lib_deps}
|
lib_deps = ${common.lib_deps}
|
||||||
build_flags = ${common.build_flags} -DNODE_FERMENTER -DHOSTNAME=\"Fermenter\"
|
build_flags = ${common.build_flags} -DNODE_FERMENTER -DHOSTNAME=\"Fermenter\"
|
||||||
|
board_build.filesystem = ${common.board_build.filesystem}
|
||||||
monitor_speed = ${common.monitor_speed}
|
monitor_speed = ${common.monitor_speed}
|
||||||
upload_protocol = espota
|
upload_flags = --auth=OtaAuthPatrixFermenter
|
||||||
;upload_port = 10.0.0.169
|
upload_protocol = ${common.upload_protocol}
|
||||||
|
upload_port = 10.0.0.171
|
||||||
|
|||||||
@ -1,24 +1,116 @@
|
|||||||
#ifdef NODE_FERMENTER
|
#ifdef NODE_FERMENTER
|
||||||
|
|
||||||
#include "patrix/bme680.h"
|
#include <ESPAsyncWebServer.h>
|
||||||
#include "patrix/tsl2561.h"
|
#include <LedControl.h>
|
||||||
|
#include <LittleFS.h>
|
||||||
|
|
||||||
DS18B20 ds18b20();
|
#include "patrix/DS18B20Sensor.h"
|
||||||
|
#include "patrix/PIDController.h"
|
||||||
|
#include "patrix/PWMOutput.h"
|
||||||
|
|
||||||
DS18B20Sensor sensor(ds18b20);
|
#define HEATER_POWER_W 30
|
||||||
|
|
||||||
PWMOutput heater();
|
AsyncWebServer server(80);
|
||||||
|
|
||||||
|
DS18B20 ds18b20("DS18B20", D4);
|
||||||
|
|
||||||
|
DS18B20Sensor input(ds18b20, 0, "");
|
||||||
|
|
||||||
|
PWMOutput heater(D2, "");
|
||||||
|
|
||||||
|
PIDController pid("fermenter", input, heater, UNIT_TEMPERATURE_C, 500, 0.00000002, 0);
|
||||||
|
|
||||||
|
auto display = LedControl(13, 14, 15, 1);
|
||||||
|
|
||||||
|
void displayDecimal(int *digit, const double value) {
|
||||||
|
const auto integer = static_cast<int>(value);
|
||||||
|
const auto decimal = static_cast<int>((value - integer) * 10) % 10;
|
||||||
|
display.setDigit(0, (*digit)++, decimal, false);
|
||||||
|
display.setDigit(0, (*digit)++, integer % 10, true);
|
||||||
|
display.setDigit(0, (*digit)++, integer / 10 % 10, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void displayLoop() {
|
||||||
|
static unsigned long lastDisplayInit = 0;
|
||||||
|
if (lastDisplayInit == 0 || millis() - lastDisplayInit > 60 * 60 * 1000) {
|
||||||
|
lastDisplayInit = millis();
|
||||||
|
display.shutdown(0, true);
|
||||||
|
display.shutdown(0, false);
|
||||||
|
display.setIntensity(0, 4);
|
||||||
|
display.clearDisplay(0);
|
||||||
|
}
|
||||||
|
auto digit = 0;
|
||||||
|
displayDecimal(&digit, input.getValue());
|
||||||
|
digit++;
|
||||||
|
digit++;
|
||||||
|
displayDecimal(&digit, pid.targetValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
void httpStatus(AsyncWebServerRequest *request) {
|
||||||
|
char buffer[256];
|
||||||
|
snprintf(buffer, sizeof buffer, R"({"target": %f, "input": %f, "outputPercent": %f, "outputPowerW": %f})", pid.targetValue, input.getValue(), heater.getPercent(), heater.getPercent() / 100.0 * HEATER_POWER_W);
|
||||||
|
request->send(200, "application/json", buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void httpTargetAdd(AsyncWebServerRequest *request) {
|
||||||
|
const auto delta = request->getParam("delta");
|
||||||
|
if (delta == nullptr) {
|
||||||
|
Log.error("Missing parameter: delta (1)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto string = delta->value();
|
||||||
|
if (string == nullptr) {
|
||||||
|
Log.error("Missing parameter: delta (2)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto value = string.toDouble();
|
||||||
|
if (isnan(value)) {
|
||||||
|
Log.error("Missing parameter: delta (3)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pid.targetValue = max(0.0, min(40.0, pid.targetValue + value));
|
||||||
|
Log.info("Set targetValue = %.1f%cC", pid.targetValue, 176);
|
||||||
|
|
||||||
|
httpStatus(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
void httpNotFound(AsyncWebServerRequest *request) {
|
||||||
|
if (request->method() == HTTP_OPTIONS) {
|
||||||
|
request->send(200);
|
||||||
|
} else {
|
||||||
|
request->send(404, "text/plain", "not found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void patrixSetup() {
|
void patrixSetup() {
|
||||||
ds18b20.setup();
|
ds18b20.setup();
|
||||||
sensor.setup();
|
|
||||||
heater.setup();
|
heater.setup();
|
||||||
|
pid.setup();
|
||||||
|
|
||||||
|
if (LittleFS.begin()) {
|
||||||
|
Log.info("Filesystem mounted.");
|
||||||
|
} else {
|
||||||
|
Log.error("Failed to mount filesystem!");
|
||||||
|
}
|
||||||
|
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", "*");
|
||||||
|
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Methods", "GET, POST, PUT");
|
||||||
|
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Headers", "Content-Type");
|
||||||
|
server.serveStatic("/", LittleFS, "/http/", "max-age=86400").setDefaultFile("index.html");
|
||||||
|
server.on("/status", httpStatus);
|
||||||
|
server.on("/status/", httpStatus);
|
||||||
|
server.on("/target/add", httpTargetAdd);
|
||||||
|
server.on("/target/add/", httpTargetAdd);
|
||||||
|
server.onNotFound(httpNotFound);
|
||||||
|
server.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
void patrixLoop() {
|
void patrixLoop() {
|
||||||
ds18b20.loop();
|
ds18b20.loop();
|
||||||
sensor.loop();
|
input.loop();
|
||||||
heater.loop();
|
pid.loop();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@ -1,74 +1,105 @@
|
|||||||
#ifndef HELLIGKEIT_DS18B20_H
|
#ifndef HELLIGKEIT_DS18B20_H
|
||||||
#define HELLIGKEIT_DS18B20_H
|
#define HELLIGKEIT_DS18B20_H
|
||||||
|
|
||||||
#include "OneWire.h"
|
#include <Adafruit_Sensor.h>
|
||||||
|
|
||||||
#include "DallasTemperature.h"
|
#include "DallasTemperature.h"
|
||||||
|
#include "IValueSensor.h"
|
||||||
|
#include "mqtt.h"
|
||||||
|
#include "OneWire.h"
|
||||||
|
|
||||||
class DS18B20 {
|
class DS18B20 {
|
||||||
|
|
||||||
enum State {
|
enum State {
|
||||||
IDLE, CONVERTING, DONE
|
IDLE, READING, COMPLETE, ERROR
|
||||||
};
|
};
|
||||||
|
|
||||||
String& name;
|
String name;
|
||||||
|
|
||||||
const int pin;
|
const int gpio;
|
||||||
|
|
||||||
OneWire oneWire;
|
OneWire oneWire;
|
||||||
|
|
||||||
DallasTemperature sensors;
|
DallasTemperature bus;
|
||||||
|
|
||||||
State state = IDLE;
|
State state = IDLE;
|
||||||
|
|
||||||
unsigned long timeout = 1000;
|
unsigned long last = 0;
|
||||||
|
|
||||||
|
boolean first = true;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
explicit DS18B20(String& name, int pin) : name(name), pin(pin), oneWire(pin), sensors(&oneWire) {
|
unsigned long interval = 5000;
|
||||||
|
|
||||||
|
unsigned long timeout = 3000;
|
||||||
|
|
||||||
|
explicit DS18B20(String name, const int gpio) : name(std::move(name)), gpio(gpio), oneWire(gpio), bus(&oneWire) {
|
||||||
// nothing
|
// nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
void begin() {
|
void setup() {
|
||||||
sensors.begin();
|
bus.begin();
|
||||||
sensors.setWaitForConversion(false);
|
bus.setWaitForConversion(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case IDLE:
|
case READING:
|
||||||
sensors.requestTemperatures();
|
if (bus.isConversionComplete()) {
|
||||||
break;
|
state = COMPLETE;
|
||||||
case CONVERTING:
|
if (first) {
|
||||||
if (sensors.isConversionComplete()) {
|
first = false;
|
||||||
|
Log.debug("DS18B20: %d devices", bus.getDeviceCount());
|
||||||
|
for (auto index = 0; index < bus.getDeviceCount(); index++) {
|
||||||
|
uint8_t address[8];
|
||||||
|
bus.getAddress(address, index);
|
||||||
|
char addressHex[19];
|
||||||
|
snprintf(addressHex, sizeof(addressHex), "0x%02X%02X%02X%02X%02X%02X%02X%02X", address[7], address[6], address[5], address[4], address[3], address[2], address[1], address[0]);
|
||||||
|
const auto temperature = bus.getTempC(address);
|
||||||
|
Log.debug(" %s: %5.1f%cC", addressHex, temperature, 176);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (millis() - last > timeout) {
|
} else if (millis() - last > timeout) {
|
||||||
Serial.printf("DS18B20 \"%s\" pin #%d: timeout", name.c_str(), pin);
|
state = ERROR;
|
||||||
|
Log.error("DS18B20 \"%s\" gpio #%d: timeout", name.c_str(), gpio);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
state = IDLE;
|
||||||
|
if (last == 0 || millis() - last >= interval) {
|
||||||
|
last = max(1UL, millis());
|
||||||
|
state = READING;
|
||||||
|
bus.requestTemperatures();
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
float getTemperatureByIndex(const int index) {
|
||||||
|
if (state != COMPLETE) {
|
||||||
class DS18B20Sensor {
|
return NAN;
|
||||||
|
}
|
||||||
DS18B20& bus;
|
const auto temperature = bus.getTempCByIndex(index);
|
||||||
|
return temperature == DEVICE_DISCONNECTED_C ? NAN : temperature;
|
||||||
const int index;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
DS18B20Sensor(DS18B20& bus, int index) : bus(bus), index(index) {
|
|
||||||
//
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup() {
|
float getTemperatureByAddress(const uint8_t *address) {
|
||||||
|
if (state != COMPLETE) {
|
||||||
|
return NAN;
|
||||||
|
}
|
||||||
|
const auto temperature = bus.getTempC(address);
|
||||||
|
return temperature == DEVICE_DISCONNECTED_C ? NAN : temperature;
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
[[nodiscard]] bool isComplete() const {
|
||||||
|
return state == COMPLETE;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool isError() const {
|
||||||
|
return state == ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //HELLIGKEIT_DS18B20_H
|
#endif
|
||||||
|
|||||||
51
src/patrix/DS18B20Sensor.h
Normal file
51
src/patrix/DS18B20Sensor.h
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#ifndef DS18B20_SENSOR_H
|
||||||
|
#define DS18B20_SENSOR_H
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "DS18B20.h"
|
||||||
|
|
||||||
|
class DS18B20Sensor final : public IValueSensor {
|
||||||
|
|
||||||
|
DS18B20& bus;
|
||||||
|
|
||||||
|
String name;
|
||||||
|
|
||||||
|
const int index;
|
||||||
|
|
||||||
|
const uint8_t *address;
|
||||||
|
|
||||||
|
float temperature = NAN;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
DS18B20Sensor(DS18B20& bus, const int index, String name) : bus(bus), name(std::move(name)), index(index), address{} {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
DS18B20Sensor(DS18B20& bus, const uint8_t address[8], String name) : bus(bus), name(std::move(name)), index(-1), address(address) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] float getValue() const override {
|
||||||
|
return temperature;
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
if (bus.isComplete()) {
|
||||||
|
if (index >= 0) {
|
||||||
|
temperature = bus.getTemperatureByIndex(index);
|
||||||
|
} else {
|
||||||
|
temperature = bus.getTemperatureByAddress(address);
|
||||||
|
}
|
||||||
|
if (!name.isEmpty()) {
|
||||||
|
mqttPublishValue(name, temperature, UNIT_TEMPERATURE_C);
|
||||||
|
}
|
||||||
|
} else if (bus.isError()) {
|
||||||
|
temperature = NAN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
14
src/patrix/IValueSensor.h
Normal file
14
src/patrix/IValueSensor.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#ifndef I_VALUE_SENSOR_H
|
||||||
|
#define I_VALUE_SENSOR_H
|
||||||
|
|
||||||
|
class IValueSensor {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual ~IValueSensor() = default;
|
||||||
|
|
||||||
|
[[nodiscard]] virtual float getValue() const = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
70
src/patrix/PIDController.h
Normal file
70
src/patrix/PIDController.h
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#ifndef PID_CONTROLLER_H
|
||||||
|
#define PID_CONTROLLER_H
|
||||||
|
|
||||||
|
#include <ArduPID.h>
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "IValueSensor.h"
|
||||||
|
#include "PWMOutput.h"
|
||||||
|
|
||||||
|
class PIDController {
|
||||||
|
|
||||||
|
const String name;
|
||||||
|
|
||||||
|
const IValueSensor& input;
|
||||||
|
|
||||||
|
PWMOutput& output;
|
||||||
|
|
||||||
|
const char *unit;
|
||||||
|
|
||||||
|
ArduPID controller;
|
||||||
|
|
||||||
|
double p = 0;
|
||||||
|
|
||||||
|
double i = 0;
|
||||||
|
|
||||||
|
double d = 0;
|
||||||
|
|
||||||
|
double inputValue = NAN;
|
||||||
|
|
||||||
|
double outputPercent = NAN;
|
||||||
|
|
||||||
|
unsigned long lastSent = 0UL;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
double targetValue = 28;
|
||||||
|
|
||||||
|
PIDController(String name, const IValueSensor& sensor, PWMOutput& pwmOutput, const char *unit, const double p, const double i, const double d)
|
||||||
|
: name(std::move(name)), input(sensor), output(pwmOutput), unit(unit), controller(), p(p), i(i), d(d) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
controller.begin(&inputValue, &outputPercent, &targetValue, p, i, d);
|
||||||
|
controller.setOutputLimits(0, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
outputPercent = 0;
|
||||||
|
inputValue = input.getValue();
|
||||||
|
if (!isnan(inputValue) && !isnan(targetValue)) {
|
||||||
|
controller.setCoefficients(p, i, d);
|
||||||
|
controller.compute();
|
||||||
|
if (!isnan(outputPercent) && outputPercent >= 0 && outputPercent <= 100) {
|
||||||
|
const auto now = millis();
|
||||||
|
if (lastSent == 0 || now - lastSent >= 5000) {
|
||||||
|
lastSent = now;
|
||||||
|
mqttPublishValue(name + "/target", targetValue, unit);
|
||||||
|
mqttPublishValue(name + "/input", inputValue, unit);
|
||||||
|
mqttPublishValue(name + "/output", outputPercent, UNIT_PERCENT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output.setPercent(outputPercent);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
48
src/patrix/PWMOutput.h
Normal file
48
src/patrix/PWMOutput.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#ifndef PWM_OUTPUT_H
|
||||||
|
#define PWM_OUTPUT_H
|
||||||
|
|
||||||
|
#define CONTROL_PWM_BITS 10
|
||||||
|
#define CONTROL_PWM_MAX (static_cast<int>(pow(2, CONTROL_PWM_BITS) - 1))
|
||||||
|
|
||||||
|
class PWMOutput {
|
||||||
|
|
||||||
|
const uint8_t gpio;
|
||||||
|
|
||||||
|
String name;
|
||||||
|
|
||||||
|
int value = 0;
|
||||||
|
|
||||||
|
double percent = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
explicit PWMOutput(const uint8_t gpio, String name): gpio(gpio), name(std::move(name)) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
analogWriteResolution(CONTROL_PWM_BITS);
|
||||||
|
setValue(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setValue(const int v) {
|
||||||
|
value = max(0, min(CONTROL_PWM_MAX, v));
|
||||||
|
percent = 100.0 * value / CONTROL_PWM_MAX;
|
||||||
|
analogWrite(gpio, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPercent(const double percent) {
|
||||||
|
setValue(static_cast<int>(percent / 100.0 * CONTROL_PWM_MAX));
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] double getPercent() const {
|
||||||
|
return percent;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] int getValue() const {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -1,18 +1,17 @@
|
|||||||
#include "Patrix.h"
|
#include "Patrix.h"
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
delay(500);
|
Log.info("Startup.");
|
||||||
Log.printf("\n\n\nStartup\n");
|
|
||||||
wifiConnect();
|
wifiConnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
wifiLoop();
|
wifiLoop();
|
||||||
mqttLoop();
|
mqttLoop();
|
||||||
if (isSetupTimeAfterBootDelay()) {
|
|
||||||
patrixSetup();
|
|
||||||
}
|
|
||||||
if (isAfterBootDelay()) {
|
if (isAfterBootDelay()) {
|
||||||
|
if (isSetupTimeAfterBootDelay()) {
|
||||||
|
patrixSetup();
|
||||||
|
}
|
||||||
patrixLoop();
|
patrixLoop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,15 +16,15 @@ public:
|
|||||||
|
|
||||||
unsigned long intervalMs;
|
unsigned long intervalMs;
|
||||||
|
|
||||||
explicit BME680(String name, const unsigned long interval_ms = 5000) : name(std::move(name)), intervalMs(interval_ms) {
|
explicit BME680(String name, const unsigned long interval_ms = 5000) : name(std::move(name)), intervalMs(interval_ms) {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
if (bme.begin()) {
|
if (bme.begin()) {
|
||||||
Log.printf("BME680 \"%s\": Initialized.\n", name.c_str());
|
Log.info("BME680 \"%s\": Initialized.", name.c_str());
|
||||||
} else {
|
} else {
|
||||||
Log.printf("BME680 \"%s\": Failed to initialize.\n", name.c_str());
|
Log.error("BME680 \"%s\": Failed to initialize.", name.c_str());
|
||||||
}
|
}
|
||||||
bme.setTemperatureOversampling(BME680_OS_8X);
|
bme.setTemperatureOversampling(BME680_OS_8X);
|
||||||
bme.setHumidityOversampling(BME680_OS_2X);
|
bme.setHumidityOversampling(BME680_OS_2X);
|
||||||
@ -37,7 +37,7 @@ public:
|
|||||||
const auto now = max(1UL, millis());
|
const auto now = max(1UL, millis());
|
||||||
if (last == 0 || now - last >= intervalMs) {
|
if (last == 0 || now - last >= intervalMs) {
|
||||||
if (bme.beginReading() == 0) {
|
if (bme.beginReading() == 0) {
|
||||||
Log.printf("BME680 \"%s\": Failed to request reading.\n", name.c_str());
|
Log.error("BME680 \"%s\": Failed to request reading.", name.c_str());
|
||||||
setup();
|
setup();
|
||||||
}
|
}
|
||||||
last = now;
|
last = now;
|
||||||
@ -52,7 +52,7 @@ public:
|
|||||||
mqttPublishValue(name + "/gas", bme.gas_resistance, "RESISTANCE_OHMS");
|
mqttPublishValue(name + "/gas", bme.gas_resistance, "RESISTANCE_OHMS");
|
||||||
mqttPublishValue(name + "/altitude", bme.readAltitude(1013.25), "ALTITUDE_M");
|
mqttPublishValue(name + "/altitude", bme.readAltitude(1013.25), "ALTITUDE_M");
|
||||||
} else {
|
} else {
|
||||||
Log.printf("BME680 \"%s\": Failed to complete reading\n", name.c_str());
|
Log.error("BME680 \"%s\": Failed to complete reading", name.c_str());
|
||||||
setup();
|
setup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,20 +24,20 @@ void mqttCallback(char *topic, const uint8_t *payload, unsigned int length) {
|
|||||||
length = min(sizeof message - 1, length);
|
length = min(sizeof message - 1, length);
|
||||||
memcpy(message, payload, length);
|
memcpy(message, payload, length);
|
||||||
*(message + length) = 0;
|
*(message + length) = 0;
|
||||||
Log.printf("MQTT received: topic=\"%s\", message=\"%s\"\n", topic, message);
|
Log.info(R"(MQTT received: topic="%s", message="%s")", topic, message);
|
||||||
if (strcmp(message, "help") == 0) {
|
if (strcmp(message, "help") == 0) {
|
||||||
Log.printf("HELP\n");
|
Log.info("HELP");
|
||||||
Log.printf(" %s\n", "help");
|
Log.info(" %s", "help");
|
||||||
Log.printf(" %s\n", "info");
|
Log.info(" %s", "info");
|
||||||
Log.printf(" %s\n", "reboot");
|
Log.info(" %s", "reboot");
|
||||||
} else if (strcmp(message, "info") == 0) {
|
} else if (strcmp(message, "info") == 0) {
|
||||||
Log.printf("INFO\n");
|
Log.info("INFO");
|
||||||
Log.printf(" %-10s %s\n", "SSID:", WiFi.SSID().c_str());
|
Log.info(" %-10s %s", "SSID:", WiFi.SSID().c_str());
|
||||||
Log.printf(" %-10s %s\n", "IP:", WiFi.localIP().toString().c_str());
|
Log.info(" %-10s %s", "IP:", WiFi.localIP().toString().c_str());
|
||||||
Log.printf(" %-10s %d\n", "RSSI:", WiFi.RSSI());
|
Log.info(" %-10s %d", "RSSI:", WiFi.RSSI());
|
||||||
Log.printf(" %-10s %s\n", "uptime:", uptimeString().c_str());
|
Log.info(" %-10s %s", "uptime:", uptimeString().c_str());
|
||||||
} else if (strcmp(message, "reboot") == 0) {
|
} else if (strcmp(message, "reboot") == 0) {
|
||||||
Log.printf("rebooting...\n");
|
Log.info("rebooting...");
|
||||||
delay(500);
|
delay(500);
|
||||||
mqtt.disconnect();
|
mqtt.disconnect();
|
||||||
delay(500);
|
delay(500);
|
||||||
@ -50,13 +50,13 @@ void mqttLoop() {
|
|||||||
mqtt.setServer("10.0.0.50", 1883);
|
mqtt.setServer("10.0.0.50", 1883);
|
||||||
if (mqtt.connect(HOSTNAME, logTopic.c_str(), 0, false, "disconnected\n")) {
|
if (mqtt.connect(HOSTNAME, logTopic.c_str(), 0, false, "disconnected\n")) {
|
||||||
yield();
|
yield();
|
||||||
mqttPublish(logTopic.c_str(), "connected\n");
|
mqttPublish(logTopic, "connected\n");
|
||||||
mqtt.setCallback(mqttCallback);
|
mqtt.setCallback(mqttCallback);
|
||||||
mqtt.subscribe(cmdTopic.c_str());
|
mqtt.subscribe(cmdTopic.c_str());
|
||||||
Log.printf("MQTT connected as \"%s\"\n", HOSTNAME);
|
Log.info("MQTT connected as \"%s\".", HOSTNAME);
|
||||||
mqttFailureMillis = 0;
|
mqttFailureMillis = 0;
|
||||||
} else {
|
} else {
|
||||||
Log.printf("Failed to connect MQTT.\n");
|
Log.error("Failed to connect MQTT.");
|
||||||
mqttFailureMillis = max(1UL, millis());
|
mqttFailureMillis = max(1UL, millis());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -100,5 +100,4 @@ void mqttPublishValue(const String& name, const String& value, const char *unit)
|
|||||||
|
|
||||||
void mqttPublish(const String& topic, const String& payload) {
|
void mqttPublish(const String& topic, const String& payload) {
|
||||||
mqtt.publish(topic.c_str(), payload.c_str());
|
mqtt.publish(topic.c_str(), payload.c_str());
|
||||||
yield();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,23 @@
|
|||||||
#include "PubSubClient.h"
|
#include "PubSubClient.h"
|
||||||
#include "wifi.h"
|
#include "wifi.h"
|
||||||
|
|
||||||
|
#define UNIT_PERCENT "UNIT_PERCENT"
|
||||||
|
#define UNIT_TEMPERATURE_C "TEMPERATURE_C"
|
||||||
|
#define UNIT_PRESSURE_HPA "PRESSURE_HPA"
|
||||||
|
#define UNIT_HUMIDITY_RELATIVE_PERCENT "HUMIDITY_RELATIVE_PERCENT"
|
||||||
|
#define UNIT_HUMIDITY_ABSOLUTE_GM3 "HUMIDITY_ABSOLUTE_GM3"
|
||||||
|
#define UNIT_IAQ "IAQ"
|
||||||
|
#define UNIT_IAQ_ACCURACY "IAQ_ACCURACY"
|
||||||
|
#define UNIT_IAQ_CO2_EQUIVALENT "IAQ_CO2_EQUIVALENT"
|
||||||
|
#define UNIT_IAQ_VOC_EQUIVALENT "IAQ_VOC_EQUIVALENT"
|
||||||
|
#define UNIT_ILLUMINANCE_LUX "ILLUMINANCE_LUX"
|
||||||
|
#define UNIT_RESISTANCE_OHMS "RESISTANCE_OHMS"
|
||||||
|
#define UNIT_ALTITUDE_M "ALTITUDE_M"
|
||||||
|
#define UNIT_POWER_W "POWER_W"
|
||||||
|
#define UNIT_POWER_KW "POWER_KW"
|
||||||
|
#define UNIT_ENERGY_WH "ENERGY_WH"
|
||||||
|
#define UNIT_ENERGY_KWH "ENERGY_KWH"
|
||||||
|
|
||||||
extern const String logTopic;
|
extern const String logTopic;
|
||||||
|
|
||||||
extern const String cmdTopic;
|
extern const String cmdTopic;
|
||||||
@ -44,7 +61,9 @@ class LogClass final : public Stream {
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
explicit LogClass(PubSubClient& mqttClient) : mqtt(mqttClient) {
|
explicit LogClass(PubSubClient& mqttClient) : mqtt(mqttClient) {
|
||||||
|
delay(500);
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
Serial.print("\n\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t write(const uint8_t data) override {
|
size_t write(const uint8_t data) override {
|
||||||
@ -82,6 +101,72 @@ public:
|
|||||||
int peek() override {
|
int peek() override {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum Level {
|
||||||
|
OFF, ERROR, WARN, INFO, DEBUG,
|
||||||
|
};
|
||||||
|
|
||||||
|
void debug(const char *format, ...) {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
log(DEBUG, format, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void info(const char *format, ...) {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
log(INFO, format, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void warn(const char *format, ...) {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
log(WARN, format, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void error(const char *format, ...) {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
log(ERROR, format, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
Level level = DEBUG;
|
||||||
|
|
||||||
|
void log(const Level level, const char *format, const va_list args) {
|
||||||
|
if (this->level < level) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
print(getTimeString().c_str());
|
||||||
|
|
||||||
|
const char *levelName;
|
||||||
|
switch (level) {
|
||||||
|
case ERROR:
|
||||||
|
levelName = "ERROR";
|
||||||
|
break;
|
||||||
|
case WARN:
|
||||||
|
levelName = "WARN";
|
||||||
|
break;
|
||||||
|
case INFO:
|
||||||
|
levelName = "INFO";
|
||||||
|
break;
|
||||||
|
case DEBUG:
|
||||||
|
levelName = "DEBUG";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
levelName = " ??? ";
|
||||||
|
}
|
||||||
|
printf(" [%-5s] ", levelName);
|
||||||
|
|
||||||
|
char buffer[256];
|
||||||
|
vsnprintf(buffer, sizeof(buffer), format, args);
|
||||||
|
println(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern LogClass Log;
|
extern LogClass Log;
|
||||||
|
|||||||
@ -21,9 +21,9 @@ public:
|
|||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
if (tsl.begin()) {
|
if (tsl.begin()) {
|
||||||
Log.printf("TSL2561 \"%s\": Initialized.\n", name.c_str());
|
Log.info("TSL2561 \"%s\": Initialized.", name.c_str());
|
||||||
} else {
|
} else {
|
||||||
Log.printf("TSL2561 \"%s\": Failed to initialize.\n", name.c_str());
|
Log.error("TSL2561 \"%s\": Failed to initialize.", name.c_str());
|
||||||
}
|
}
|
||||||
tsl.enableAutoRange(true);
|
tsl.enableAutoRange(true);
|
||||||
tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_402MS);
|
tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_402MS);
|
||||||
@ -45,7 +45,7 @@ private:
|
|||||||
tsl.getLuminosity(&broadband, &ir);
|
tsl.getLuminosity(&broadband, &ir);
|
||||||
const auto illuminance = tsl.calculateLux(broadband, ir);
|
const auto illuminance = tsl.calculateLux(broadband, ir);
|
||||||
if (illuminance == 65536) {
|
if (illuminance == 65536) {
|
||||||
Log.printf("TSL2561 \"%s\": Failed to read.\n", name.c_str());
|
Log.error("TSL2561 \"%s\": Failed to read.", name.c_str());
|
||||||
setup();
|
setup();
|
||||||
} else {
|
} else {
|
||||||
mqttPublishValue(name + "/illuminance", illuminance, "ILLUMINANCE_LUX");
|
mqttPublishValue(name + "/illuminance", illuminance, "ILLUMINANCE_LUX");
|
||||||
|
|||||||
@ -23,7 +23,7 @@ void wifiConnect() {
|
|||||||
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
|
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
|
||||||
configTime(TZ_Europe_Berlin, NTP_SERVER);
|
configTime(TZ_Europe_Berlin, NTP_SERVER);
|
||||||
ArduinoOTA.onStart([]() {
|
ArduinoOTA.onStart([]() {
|
||||||
Log.printf("OTA begin...\n");
|
Log.info("OTA begin...");
|
||||||
});
|
});
|
||||||
ArduinoOTA.onError([](const ota_error_t error) {
|
ArduinoOTA.onError([](const ota_error_t error) {
|
||||||
const char *name;
|
const char *name;
|
||||||
@ -42,10 +42,10 @@ void wifiConnect() {
|
|||||||
name = "[???]";
|
name = "[???]";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Log.printf("OTA error #%d: %s\n", error, name);
|
Log.error("OTA error #%d: %s", error, name);
|
||||||
});
|
});
|
||||||
ArduinoOTA.onEnd([]() {
|
ArduinoOTA.onEnd([]() {
|
||||||
Log.printf("OTA success\n");
|
Log.info("OTA success");
|
||||||
});
|
});
|
||||||
ArduinoOTA.begin();
|
ArduinoOTA.begin();
|
||||||
yield();
|
yield();
|
||||||
@ -93,18 +93,18 @@ void timeLoop() {
|
|||||||
if (now > 1700000000) {
|
if (now > 1700000000) {
|
||||||
timeSetSince = now;
|
timeSetSince = now;
|
||||||
lastHour = nowHour;
|
lastHour = nowHour;
|
||||||
Log.printf("Got time: %s\n", getTimeString().c_str());
|
Log.info("Got time: %s.", getTimeString().c_str());
|
||||||
Log.printf("Delaying boot for %d seconds.\n", BOOT_DELAY_SEC);
|
Log.info("Delaying boot for %d seconds.", BOOT_DELAY_SEC);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (lastHour != nowHour) {
|
if (lastHour != nowHour) {
|
||||||
lastHour = nowHour;
|
lastHour = nowHour;
|
||||||
Log.printf("%s\n", getTimeString().c_str());
|
Log.info("Alive.");
|
||||||
}
|
}
|
||||||
if (!bootDelayOver) {
|
if (!bootDelayOver) {
|
||||||
bootDelayOver = time(nullptr) - timeSetSince > BOOT_DELAY_SEC;
|
bootDelayOver = time(nullptr) - timeSetSince > BOOT_DELAY_SEC;
|
||||||
if (bootDelayOver) {
|
if (bootDelayOver) {
|
||||||
Log.printf("Boot delay complete.\n");
|
Log.info("Boot delay complete.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -115,7 +115,7 @@ void wifiLoop() {
|
|||||||
if (WiFi.localIP() == 0UL) {
|
if (WiFi.localIP() == 0UL) {
|
||||||
if (wifiConnected) {
|
if (wifiConnected) {
|
||||||
wifiConnected = false;
|
wifiConnected = false;
|
||||||
Log.printf("WiFi disconnected.\n");
|
Log.warn("WiFi disconnected.");
|
||||||
wifiConnect();
|
wifiConnect();
|
||||||
} else if (wifiConnectBeginMillis == 0 || millis() - wifiConnectBeginMillis >= WIFI_TIMEOUT_MS) {
|
} else if (wifiConnectBeginMillis == 0 || millis() - wifiConnectBeginMillis >= WIFI_TIMEOUT_MS) {
|
||||||
WiFi.disconnect();
|
WiFi.disconnect();
|
||||||
@ -126,7 +126,7 @@ void wifiLoop() {
|
|||||||
if (!wifiConnected) {
|
if (!wifiConnected) {
|
||||||
wifiConnected = true;
|
wifiConnected = true;
|
||||||
wifiConnectBeginMillis = 0;
|
wifiConnectBeginMillis = 0;
|
||||||
Log.printf("WiFi connected as \"%s\" (%s)\n", HOSTNAME, WiFi.localIP().toString().c_str());
|
Log.info("WiFi connected as \"%s\" (%s).", HOSTNAME, WiFi.localIP().toString().c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
uptimeLoop();
|
uptimeLoop();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user