switch to ha-mqtt library, remove altitude
This commit is contained in:
parent
dfcbe7e081
commit
348e2694db
@ -10,7 +10,6 @@ namespace Bme {
|
||||
float temp;
|
||||
float humidity;
|
||||
float pressure;
|
||||
float altitude;
|
||||
float readTemp() {
|
||||
char buf[10];
|
||||
sprintf(buf, "%.1f", bme.readTemperature() - 2);
|
||||
@ -27,7 +26,6 @@ namespace Bme {
|
||||
readTemp();
|
||||
readHumidity();
|
||||
pressure = bme.readPressure() / 100;
|
||||
altitude = bme.readAltitude(1006);
|
||||
}
|
||||
} data;
|
||||
|
||||
|
||||
90
include/devices.h
Normal file
90
include/devices.h
Normal file
@ -0,0 +1,90 @@
|
||||
#pragma once
|
||||
|
||||
#define MAIN_DEVICE_ID "esp_clock"
|
||||
#define SENSOR_ID "bme280"
|
||||
|
||||
#include "ha.h"
|
||||
#include "display.h"
|
||||
|
||||
using namespace Ha;
|
||||
|
||||
namespace Devices {
|
||||
|
||||
auto espClockDevice = &DeviceConfig::create(MAIN_DEVICE_ID)
|
||||
.withName("ESP Clock")
|
||||
.withManufacturer("Espressif")
|
||||
.withModel("Esp8266 D1 Mini")
|
||||
.withArea("Living room");
|
||||
|
||||
Sensor* sensor = Builder<TemperatureSensor>::instance(SENSOR_ID)
|
||||
.withValueTemplate("{{ value_json.temperature }}")
|
||||
.asDevice(&DeviceConfig::create("esp-clock-living-room")
|
||||
.withName("Living room")
|
||||
.withModel("BPE280")
|
||||
.withArea("Living room")
|
||||
.withParent(espClockDevice)
|
||||
)
|
||||
.addSecondary(Builder<HumiditySensor>::instance(SENSOR_ID).withValueTemplate("{{ value_json.humidity }}").build())
|
||||
.addSecondary(Builder<PressureSensor>::instance(SENSOR_ID).withValueTemplate("{{ value_json.pressure }}").build())
|
||||
.build();
|
||||
|
||||
Switch* ledMqtt = Builder<Switch>::instance(new Switch{ "Led", "led",
|
||||
[](const char* msg) {
|
||||
strcmp("ON", msg) == 0 ? digitalWrite(LED_BUILTIN, LOW) : digitalWrite(LED_BUILTIN, HIGH);
|
||||
ledMqtt->updateState(!digitalRead(LED_BUILTIN));
|
||||
}
|
||||
}).withStateTopic().restoreFromState().build();
|
||||
|
||||
auto brightnessMqtt = Builder<Number>::instance(new Number{ "Brightness", "brightness", BRIGHTNESS_MIN, BRIGHTNESS_MAX, BRIGHTNESS_STEP,
|
||||
[](const char* msg) {
|
||||
Display::Brightness::set(String{ msg }.toInt());
|
||||
}
|
||||
}).withStateTopic().restoreFromState().build();
|
||||
|
||||
auto hourFormatMqtt = Builder<Switch>::instance(new Switch{ "Format 24h", "format_24h",
|
||||
[](const char* msg) {
|
||||
strcmp("ON", msg) == 0 ? Display::changeHourFormat24(true) : Display::changeHourFormat24(false);
|
||||
}
|
||||
}).withStateTopic().restoreFromState().build();
|
||||
|
||||
auto button =
|
||||
Builder<Button>::instance(new Button{"Restart", "restart",
|
||||
[](const char* msg) {
|
||||
if (strcmp("PRESS", msg) == 0) ESP.restart();
|
||||
}
|
||||
})
|
||||
.asDevice(espClockDevice)
|
||||
.addSecondary(
|
||||
Builder<Button>::instance(new Button{"Display sensor data", "display_sensor_data",
|
||||
[](const char* msg) {
|
||||
if (strcmp("PRESS", msg) == 0 && !Display::tDisplaySensor.isEnabled()) {
|
||||
Bme::data.readAll();
|
||||
Display::tDisplaySensor.restart();
|
||||
};
|
||||
}
|
||||
}).build()
|
||||
)
|
||||
.addSecondary(ledMqtt)
|
||||
.addConfiguration(brightnessMqtt)
|
||||
.addConfiguration(hourFormatMqtt)
|
||||
.build();
|
||||
|
||||
void publishBme280() {
|
||||
StaticJsonDocument<255> jsonDoc;
|
||||
jsonDoc["temperature"] = Bme::data.temp;
|
||||
jsonDoc["humidity"] = Bme::data.humidity;
|
||||
jsonDoc["pressure"] = Bme::data.pressure;
|
||||
char message[255];
|
||||
serializeJson(jsonDoc, message);
|
||||
sensor->updateState(message);
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Display::hourFormatChangedCallback = []{
|
||||
hourFormatMqtt->updateState(Display::hourFormat24);
|
||||
};
|
||||
Display::Brightness::brightnessChangedCallback = []{
|
||||
brightnessMqtt->updateState(Display::Brightness::current);
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -39,9 +39,6 @@ namespace Display {
|
||||
|
||||
bool hourFormat24 = false;
|
||||
void (*hourFormatChangedCallback)();
|
||||
void onHourFormatChanged(void (*f)()) {
|
||||
hourFormatChangedCallback = f;
|
||||
}
|
||||
|
||||
// Create display object
|
||||
Adafruit_7segment clockDisplay = Adafruit_7segment();
|
||||
@ -56,10 +53,6 @@ namespace Display {
|
||||
brightnessChangedCallback();
|
||||
}
|
||||
|
||||
void onChanged(void (*f)()) {
|
||||
brightnessChangedCallback = f;
|
||||
}
|
||||
|
||||
void change(bool increase) {
|
||||
increase ? set(current + BRIGHTNESS_STEP) : set(current - BRIGHTNESS_STEP);
|
||||
}
|
||||
|
||||
182
include/ha.h
182
include/ha.h
@ -1,182 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include "display.h"
|
||||
|
||||
#define JSON_SIZE 512
|
||||
#define TOPIC_SIZE 255
|
||||
|
||||
namespace Ha {
|
||||
|
||||
struct Component {
|
||||
const char* name;
|
||||
const char* id;
|
||||
const char* type;
|
||||
char configTopic[TOPIC_SIZE];
|
||||
|
||||
Component(const char* name, const char* id, const char* type) {
|
||||
this->name = name;
|
||||
this->id = id;
|
||||
this->type = type;
|
||||
sprintf(configTopic, "homeassistant/%s/esp_clock/%s/config", type, id);
|
||||
}
|
||||
|
||||
virtual void buildUniqueId(char* uniqueId) = 0;
|
||||
|
||||
virtual void buildConfig(JsonDocument& jsonDoc) {
|
||||
buildDeviceConfig(jsonDoc);
|
||||
jsonDoc["name"] = name;
|
||||
char uniqueId[50];
|
||||
buildUniqueId(uniqueId);
|
||||
jsonDoc["unique_id"] = uniqueId;
|
||||
}
|
||||
|
||||
virtual void buildDeviceConfig(JsonDocument& jsonDoc) {
|
||||
JsonObject device = jsonDoc.createNestedObject("device");
|
||||
device["name"] = "ESP Clock";
|
||||
device["model"] = "Esp8266 D1 Mini";
|
||||
device["manufacturer"] = "Espressif";
|
||||
device["suggested_area"] = "Living room";
|
||||
JsonArray connections = device.createNestedArray("connections");
|
||||
JsonArray mac = connections.createNestedArray();
|
||||
mac.add("mac");
|
||||
mac.add(WiFi.macAddress());
|
||||
JsonArray identifiers = device.createNestedArray("identifiers");
|
||||
identifiers.add("esp-clock");
|
||||
}
|
||||
};
|
||||
|
||||
typedef void (*onMessage)(const char* msg);
|
||||
struct Command : Component {
|
||||
char commandTopic[TOPIC_SIZE];
|
||||
char stateTopic[TOPIC_SIZE];
|
||||
onMessage f;
|
||||
void (*publishState)();
|
||||
|
||||
Command(const char* name, const char* id, const char* type, onMessage f, void (*publishState)() = nullptr) : Component(name, id, type) {
|
||||
this->f = f;
|
||||
this->publishState = publishState;
|
||||
}
|
||||
|
||||
void buildUniqueId(char* uniqueId) override {
|
||||
sprintf(uniqueId, "esp_clock_%s", id);
|
||||
}
|
||||
|
||||
void buildConfig(JsonDocument& jsonDoc) override {
|
||||
Component::buildConfig(jsonDoc);
|
||||
jsonDoc["command_topic"] = commandTopic;
|
||||
if (stateTopic[0]) jsonDoc["state_topic"] = stateTopic;
|
||||
}
|
||||
|
||||
Command* withStateTopic() {
|
||||
sprintf(stateTopic, "homeassistant/%s/esp_clock/%s/state", type, id);
|
||||
return this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct Button : Command {
|
||||
static constexpr const char* type = "button";
|
||||
|
||||
Button(const char* name, const char* id, onMessage f) : Command(name, id, type, f) {
|
||||
sprintf(commandTopic, "homeassistant/%s/esp_clock/%s", type, id);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct Switch : Command {
|
||||
static constexpr const char* type = "switch";
|
||||
|
||||
Switch(const char* name, const char* id, onMessage f, void (*publishState)()) : Command(name, id, type, f, publishState) {
|
||||
sprintf(commandTopic, "homeassistant/%s/esp_clock/%s/set", type, id);
|
||||
}
|
||||
|
||||
void buildConfig(JsonDocument& jsonDoc) override {
|
||||
Command::buildConfig(jsonDoc);
|
||||
jsonDoc["retain"] = true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct Brightness : Command {
|
||||
static constexpr const char* type = "number";
|
||||
|
||||
Brightness(const char* name, const char* id, onMessage f, void (*publishState)()) : Command(name, id, type, f, publishState) {
|
||||
sprintf(commandTopic, "homeassistant/%s/esp_clock/%s", type, id);
|
||||
}
|
||||
|
||||
void buildConfig(JsonDocument& jsonDoc) override {
|
||||
Command::buildConfig(jsonDoc);
|
||||
jsonDoc["retain"] = true;
|
||||
jsonDoc["min"] = BRIGHTNESS_MIN;
|
||||
jsonDoc["max"] = BRIGHTNESS_MAX;
|
||||
jsonDoc["step"] = BRIGHTNESS_STEP;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct Sensor : Component {
|
||||
const char* deviceClass;
|
||||
const char* unitMeasure;
|
||||
const char* valueTemplate;
|
||||
static constexpr const char* stateTopic = "homeassistant/sensor/esp_clock/state";
|
||||
|
||||
Sensor(const char* name, const char* id) : Component(name, id, "sensor") {
|
||||
}
|
||||
|
||||
void buildUniqueId(char* uniqueId) override {
|
||||
sprintf(uniqueId, "living_room_%s", id);
|
||||
}
|
||||
|
||||
void buildConfig(JsonDocument& jsonDoc) override {
|
||||
Component::buildConfig(jsonDoc);
|
||||
jsonDoc["device_class"] = deviceClass;
|
||||
jsonDoc["unit_of_measurement"] = unitMeasure;
|
||||
jsonDoc["value_template"] = valueTemplate;
|
||||
jsonDoc["state_topic"] = stateTopic;
|
||||
}
|
||||
|
||||
void buildDeviceConfig(JsonDocument& jsonDoc) override {
|
||||
JsonObject device = jsonDoc.createNestedObject("device");
|
||||
device["name"] = "Living room";
|
||||
device["model"] = "BPM280";
|
||||
device["suggested_area"] = "Living room";
|
||||
device["via_device"] = "esp-clock";
|
||||
JsonArray identifiers = device.createNestedArray("identifiers");
|
||||
identifiers.add("esp-clock-living-room");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct TemperatureSensor : Sensor {
|
||||
TemperatureSensor(const char* name, const char* id) : Sensor(name, id) {
|
||||
deviceClass = "temperature";
|
||||
unitMeasure = "°C";
|
||||
valueTemplate = "{{ value_json.temperature }}";
|
||||
}
|
||||
};
|
||||
|
||||
struct HumiditySensor : Sensor {
|
||||
HumiditySensor(const char* name, const char* id) : Sensor(name, id) {
|
||||
deviceClass = "humidity";
|
||||
unitMeasure = "%";
|
||||
valueTemplate = "{{ value_json.humidity }}";
|
||||
}
|
||||
};
|
||||
|
||||
struct PressureSensor : Sensor {
|
||||
PressureSensor(const char* name, const char* id) : Sensor(name, id) {
|
||||
deviceClass = "pressure";
|
||||
unitMeasure = "hPa";
|
||||
valueTemplate = "{{ value_json.pressure }}";
|
||||
}
|
||||
};
|
||||
|
||||
struct AltitudeSensor : Sensor {
|
||||
AltitudeSensor(const char* name, const char* id) : Sensor(name, id) {
|
||||
deviceClass = "distance";
|
||||
unitMeasure = "m";
|
||||
valueTemplate = "{{ value_json.altitude }}";
|
||||
}
|
||||
};
|
||||
}
|
||||
153
include/mqtt.h
153
include/mqtt.h
@ -1,153 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <AsyncMqttClient.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include "ha.h"
|
||||
#include "bme.h"
|
||||
#include "display.h"
|
||||
|
||||
#define MQTT_HOST IPAddress(192, 168, 5, 11)
|
||||
#define MQTT_PORT 1883
|
||||
|
||||
namespace Mqtt {
|
||||
|
||||
void publishInit();
|
||||
void publishBme280();
|
||||
void connect();
|
||||
void disconnect();
|
||||
Task tReConnect(5 * TASK_MINUTE, TASK_FOREVER, connect, &ts);
|
||||
Task tPublishInit(TASK_IMMEDIATE, TASK_ONCE, publishInit, &ts);
|
||||
|
||||
AsyncMqttClient client;
|
||||
|
||||
const char* espClockTopic = "homeassistant/+/esp_clock/#";
|
||||
|
||||
void connect() {
|
||||
client.connect();
|
||||
}
|
||||
|
||||
void disconnect() {
|
||||
client.unsubscribe(espClockTopic);
|
||||
client.disconnect();
|
||||
}
|
||||
|
||||
uint16_t publish(const char* topic, const char* message) {
|
||||
return client.publish(topic, 0, true, message);
|
||||
}
|
||||
|
||||
Ha::Sensor* sensors[] = {
|
||||
new Ha::TemperatureSensor{"Temperature", "temperature"},
|
||||
new Ha::HumiditySensor{"Humidity", "humidity"},
|
||||
new Ha::PressureSensor{"Pressure", "pressure"},
|
||||
new Ha::AltitudeSensor{"Altitude", "altitude"}
|
||||
};
|
||||
|
||||
Ha::Command* ledMqtt = (new Ha::Switch{"Led", "led",
|
||||
[](const char* msg) {
|
||||
String{ "ON" }.equals(msg) ? digitalWrite(LED_BUILTIN, LOW) : digitalWrite(LED_BUILTIN, HIGH);
|
||||
},
|
||||
[]() {
|
||||
publish(ledMqtt->stateTopic, digitalRead(LED_BUILTIN) ? "OFF" : "ON");
|
||||
}
|
||||
})->withStateTopic();
|
||||
|
||||
Ha::Command* brightnessMqtt = (new Ha::Brightness{ "Brightness", "brightness",
|
||||
[](const char* msg) {
|
||||
Display::Brightness::set(String{ msg }.toInt());
|
||||
},
|
||||
[]() {
|
||||
char message[32];
|
||||
sprintf(message, "%u", Display::Brightness::current);
|
||||
publish(brightnessMqtt->stateTopic, message);
|
||||
}
|
||||
})->withStateTopic();
|
||||
|
||||
Ha::Command* hourFormatMqtt = (new Ha::Switch{"Format 24h", "format_24h",
|
||||
[](const char* msg) {
|
||||
String{ "ON" }.equals(msg) ? Display::changeHourFormat24(true) : Display::changeHourFormat24(false);
|
||||
},
|
||||
[]() {
|
||||
publish(hourFormatMqtt->stateTopic, Display::hourFormat24 ? "ON" : "OFF");
|
||||
}
|
||||
})->withStateTopic();
|
||||
|
||||
Ha::Command* switches[] = {
|
||||
new Ha::Button{"Restart", "restart",
|
||||
[](const char* msg) {
|
||||
if (String { "PRESS" }.equals(msg)) ESP.restart();
|
||||
}
|
||||
},
|
||||
new Ha::Button{"Display sensor data", "display_sensor_data",
|
||||
[](const char* msg) {
|
||||
if (String { "PRESS" }.equals(msg) && !Display::tDisplaySensor.isEnabled()) {
|
||||
Bme::data.readAll();
|
||||
Display::tDisplaySensor.restart();
|
||||
};
|
||||
}
|
||||
},
|
||||
ledMqtt,
|
||||
hourFormatMqtt,
|
||||
brightnessMqtt
|
||||
};
|
||||
|
||||
void publishComponentConfig(Ha::Component& component) {
|
||||
StaticJsonDocument<JSON_SIZE> jsonDoc;
|
||||
component.buildConfig(jsonDoc);
|
||||
|
||||
char message[JSON_SIZE];
|
||||
serializeJson(jsonDoc, message);
|
||||
|
||||
publish(component.configTopic, message);
|
||||
}
|
||||
|
||||
void publishInit() {
|
||||
for (Ha::Component* cmp : sensors) {
|
||||
publishComponentConfig(*cmp);
|
||||
}
|
||||
for (Ha::Component* cmp : switches) {
|
||||
publishComponentConfig(*cmp);
|
||||
}
|
||||
ts.deleteTask(tPublishInit);
|
||||
}
|
||||
|
||||
void publishBme280() {
|
||||
StaticJsonDocument<255> jsonDoc;
|
||||
jsonDoc["temperature"] = Bme::data.temp;
|
||||
jsonDoc["humidity"] = Bme::data.humidity;
|
||||
jsonDoc["pressure"] = Bme::data.pressure;
|
||||
jsonDoc["altitude"] = Bme::data.altitude;
|
||||
char message[255];
|
||||
serializeJson(jsonDoc, message);
|
||||
publish(Ha::Sensor::stateTopic, message);
|
||||
}
|
||||
|
||||
void onMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) {
|
||||
char msg[len + 1];
|
||||
memcpy(msg, payload, len);
|
||||
msg[len] = 0;
|
||||
for (Ha::Command* cmd : switches) {
|
||||
if (String{ cmd->commandTopic }.equals(topic)) {
|
||||
cmd->f(msg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Display::Brightness::onChanged(brightnessMqtt->publishState);
|
||||
Display::onHourFormatChanged(hourFormatMqtt->publishState);
|
||||
client.onConnect([](bool sessionPresent) {
|
||||
tPublishInit.enable();
|
||||
client.subscribe(espClockTopic, 0);
|
||||
tReConnect.disable();
|
||||
Serial.println("Connected to MQTT");
|
||||
});
|
||||
client.onDisconnect([](AsyncMqttClientDisconnectReason reason) {
|
||||
tReConnect.enableDelayed();
|
||||
Serial.println("Disconnected from MQTT");
|
||||
});
|
||||
client.onMessage(onMessage);
|
||||
client.setServer(MQTT_HOST, MQTT_PORT);
|
||||
Serial.println("Connecting to MQTT...");
|
||||
}
|
||||
}
|
||||
@ -7,10 +7,13 @@ namespace Ota {
|
||||
|
||||
void setup() {
|
||||
ArduinoOTA.onStart([]() {
|
||||
Serial.println("Start");
|
||||
Serial.println("Starting OTA");
|
||||
Mqtt::publishCleanupConfig();
|
||||
delay(2000);
|
||||
Mqtt::disconnect();
|
||||
});
|
||||
ArduinoOTA.onEnd([]() {
|
||||
Serial.println("\nEnd");
|
||||
Serial.println("\nOTA Finished");
|
||||
});
|
||||
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
|
||||
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
|
||||
|
||||
@ -18,11 +18,9 @@ lib_deps =
|
||||
adafruit/Adafruit GFX Library@^1.10.12
|
||||
adafruit/Adafruit BusIO@^1.9.8
|
||||
jchristensen/Timezone@^1.2.4
|
||||
marvinroger/AsyncMqttClient@^0.9.0
|
||||
arkhipenko/TaskScheduler@^3.7.0
|
||||
adafruit/Adafruit Unified Sensor @ ^1.1.4
|
||||
adafruit/Adafruit BME280 Library@^2.2.4
|
||||
bblanchon/ArduinoJson@6.16.1
|
||||
https://git.hodos.ro/arduino/ha-mqtt.git@^1.0.0
|
||||
build_flags = -D WIFI_ALWAYS_ON=1
|
||||
|
||||
[env:laptop_home]
|
||||
|
||||
@ -6,16 +6,19 @@ void onButtonPressed();
|
||||
void onLed();
|
||||
void onButtonCallback();
|
||||
|
||||
#define MQTT_HOST IPAddress(192, 168, 5, 11)
|
||||
#define MQTT_PORT 1883
|
||||
|
||||
#include <TaskScheduler.h>
|
||||
Scheduler ts;
|
||||
Task tCheckWifi(5 * TASK_MINUTE, TASK_ONCE, checkWifiCallback, &ts);
|
||||
Task tWifiConnected(TASK_IMMEDIATE, TASK_ONCE, onWifiConnected, &ts);
|
||||
|
||||
#include "wifi.h"
|
||||
#include "mqtt.h"
|
||||
#include "display.h"
|
||||
#include "bme.h"
|
||||
#include "ntp_time.h"
|
||||
#include "wifi.h"
|
||||
#include "devices.h"
|
||||
#include "mqtt.h"
|
||||
#include "ota.h"
|
||||
|
||||
#define BUTTON D3
|
||||
@ -26,7 +29,7 @@ Task tButton(TASK_IMMEDIATE, TASK_ONCE, []() {
|
||||
Display::tDisplaySensor.restart();
|
||||
}, &ts);
|
||||
Task tLed(TASK_IMMEDIATE, TASK_ONCE, []() {
|
||||
Mqtt::ledMqtt->publishState();
|
||||
Devices::ledMqtt->updateState(!digitalRead(LED_BUILTIN));
|
||||
}, &ts);
|
||||
Task tReadBme(TASK_MINUTE, TASK_FOREVER, []() {
|
||||
static float lastTemp = 0;
|
||||
@ -34,7 +37,7 @@ Task tReadBme(TASK_MINUTE, TASK_FOREVER, []() {
|
||||
float humidity = Bme::data.humidity;
|
||||
Bme::data.readAll();
|
||||
if ((temp == Bme::data.temp) && (humidity == Bme::data.humidity)) return;
|
||||
Mqtt::publishBme280();
|
||||
Devices::publishBme280();
|
||||
if (abs(lastTemp - Bme::data.temp) > 0.2) {
|
||||
lastTemp = Bme::data.temp;
|
||||
Display::tDisplaySensor.setIterations(DISPLAY_SENSOR_ITERATIONS*2);
|
||||
@ -52,8 +55,9 @@ void setup() {
|
||||
Display::setup();
|
||||
Ota::setup();
|
||||
Ntp::setup();
|
||||
Mqtt::setup();
|
||||
Bme::setup();
|
||||
Mqtt::setup(&ts);
|
||||
Devices::setup();
|
||||
|
||||
Wifi::setup();
|
||||
|
||||
@ -72,7 +76,7 @@ void onWifiConnected() {
|
||||
Serial.println("Wifi connected event");
|
||||
Wifi::printStatus();
|
||||
Ota::tLoop.enable();
|
||||
Mqtt::connect();
|
||||
Mqtt::tReConnect.enable();
|
||||
if (time_t newTime = Ntp::updateTime()) {
|
||||
Serial.println(asctime(localtime(&newTime)));
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user