- The bit-banged WS2812 update disables interrupts (about 30 us per pixel), which made the lit tube stay on longer and flash. neoShow() now only sends when the pixels changed (fixed colour was resent every second) and waits for the dark gap between tubes; the bit-bang strip has no headroom pixels. This also fixed digits that seemed to hang. - 4 WS2812 on this board, one per tube (not 8) - Saving the firmware URL in the web UI no longer starts an HTTP update; never update from an empty URL - Restart once after the first switch from AP mode to WiFi, so ArduinoOTA and MQTT start on the real network - Optional web UI password (WEB_USER/WEB_PASSWORD in secrets.h); /getConfiguration returns the stored WiFi and MQTT passwords - Cathode protect: random mode now starts at a random tube (the +-1 start digits were swapped and then overwritten) - Apply the unused gamma table to wheel colours - LOOP_DIAG (off by default): main-loop stalls in /getCurrentInfos, which now also reports uptime and free heap Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
453 lines
19 KiB
Arduino
453 lines
19 KiB
Arduino
#ifdef USE_MQTT
|
|
//=========================================================================================================================
|
|
// mqtt.ino - Home Assistant / MQTT integration (compiled only if USE_MQTT is defined for the active CLOCK_NN in clocks.h)
|
|
//
|
|
// Library: ArduinoHA 2.x (https://github.com/dawidchyrzynski/arduino-home-assistant), which wraps PubSubClient
|
|
// (https://pubsubclient.knolleary.net/) and adds Home Assistant MQTT Discovery on top of it. The HA* objects
|
|
// below publish their discovery config automatically whenever the broker connection is (re)established.
|
|
// (Rewritten for ArduinoHA 2.1: the bundled 1.3 had no light/number/select/button entities.)
|
|
//
|
|
// Entities (all grouped under one HA device, unique IDs prefixed with the MAC address):
|
|
// Sensors: temperature/humidity/pressure/lux/radar (whichever exist on this clock), WiFi signal
|
|
// Controls: Tubes (switch, runtime only), Day/Night brightness (numbers), Auto dim (switch),
|
|
// Cathode protect (button); with USE_NEOPIXEL also Backlight (light: on/off, brightness, colour)
|
|
// and LED effect (select).
|
|
// Changes made on the clock's own web page are reported back to HA by mqttSend().
|
|
// Settings changed from HA are saved to EEPROM a few seconds after the last change (one flash write per burst).
|
|
//
|
|
// MASTER / SLAVE sensor-sharing architecture:
|
|
// Every clock that defines USE_MQTT connects to the same broker (prm.mqttBrokerAddr/User/Psw, set on the web UI) and
|
|
// PUBLISHES its own local sensors. A clock that does NOT have its own sensor (or wants to reuse another clock's
|
|
// reading) can instead be built with USE_MASTER_CLOCK, and SUBSCRIBE to another clock's already-published topics:
|
|
// USE_MASTER_TEMP + MASTER_TEMPERATURE_TOPIC -> mirrors the master's temperature into local temperature[] array
|
|
// USE_MASTER_HUMID + MASTER_HUMIDITY_TOPIC -> mirrors the master's humidity into local humid[] array
|
|
// USE_MASTER_RADAR + MASTER_RADAR_TOPIC -> mirrors the master's PIR/radar presence state into mqttRadarON
|
|
// If a "slave" clock DOES also have its own local RADAR_PIN wired, the local pin always wins - the radar topic
|
|
// subscription is skipped in onMqttConnected(), and checkTubePowerOnOff() prefers digitalRead(RADAR_PIN).
|
|
// NOTE: the topic layout changed with ArduinoHA 2.x: sensor values are now published on
|
|
// "<data prefix>/<device id>/<entity id>/stat_t" (data prefix "aha" by default), so MASTER_*_TOPIC settings
|
|
// written for the old library must be updated.
|
|
//
|
|
// Call pattern from the core .ino: setupMqtt() is called once from setup() when USE_MQTT is defined (the broker
|
|
// address/user/password are read then, so a change on the web UI needs a reboot); mqttSend() is called every loop()
|
|
// iteration while WiFi is connected and prm.mqttEnable is set. It pumps mqtt.loop() on every call and refreshes
|
|
// sensor values every prm.mqttBrokerRefresh seconds (at least every MQTT_MIN_REFRESH seconds).
|
|
//_______________________________________________________________________________________________________________________
|
|
//To use MQTT services the following settings should be defined in clocks.h
|
|
//#define USE_MQTT
|
|
//#define MQTT_PREFIX "homeassistant" //HA discovery prefix (Home Assistant's default is "homeassistant")
|
|
//#define USE_MASTER_CLOCK //enable it, if you want to get any data from MASTER CLOCK. This will be the sensor#0
|
|
//#define USE_MASTER_TEMP //enable it, if you want to get temperature from MASTER CLOCK
|
|
//#define USE_MASTER_HUMID //enable it, if you want to get humidity from MASTER CLOCK
|
|
//#define USE_MASTER_RADAR //enable it, if you want to get radar state from MASTER CLOCK
|
|
//#define MASTER_TEMPERATURE_TOPIC "..."
|
|
//#define MASTER_HUMIDITY_TOPIC "..."
|
|
//#define MASTER_RADAR_TOPIC "..."
|
|
//_______________________________________________________________________________________________________________________
|
|
|
|
#include <ArduinoHA.h> //https://github.com/dawidchyrzynski/arduino-home-assistant
|
|
|
|
#if !defined(MQTT_PREFIX)
|
|
#define MQTT_PREFIX "UniClock32" //HA discovery prefix (upstream default; Home Assistant itself listens on "homeassistant")
|
|
#endif
|
|
#define MQTT_MIN_REFRESH 10 //seconds between sensor refreshes if prm.mqttBrokerRefresh is lower
|
|
#define MQTT_SAVE_DELAY 3000 //ms after the last change from HA before the settings are written to EEPROM
|
|
#define MQTT_WHITE_INDEX 192 //same as WHITE_INDEX in z_neopixel.ino (that file is compiled after this one)
|
|
|
|
byte mac[6]; //this device's WiFi MAC, used as the HA device ID
|
|
char masterTemperatureTopic[80] = ""; //resolved from MASTER_TEMPERATURE_TOPIC (clocks.h) - topic this clock SUBSCRIBES to
|
|
char masterHumidityTopic[80] = ""; //resolved from MASTER_HUMIDITY_TOPIC (clocks.h) - topic this clock SUBSCRIBES to
|
|
char masterRadarTopic[80] = ""; //resolved from MASTER_RADAR_TOPIC (clocks.h) - topic this clock SUBSCRIBES to
|
|
byte MASTERtempPtr=0;
|
|
byte MASTERhumidPtr=0;
|
|
char mqttConfigUrl[40];
|
|
unsigned long mqttSaveRequested = 0; //millis() of the last change from HA that still has to be saved, 0 = none
|
|
|
|
WiFiClient client;
|
|
HADevice device;
|
|
HAMqtt mqtt(client, device, 20); //up to 20 entities
|
|
|
|
//Sensors that only some clocks have are created in setupMqtt(): every constructed entity registers itself with
|
|
//mqtt and is published to HA, so unused ones would show up as empty entities.
|
|
HASensorNumber* mqttTemp = nullptr;
|
|
HASensorNumber* mqttHumid = nullptr;
|
|
HASensorNumber* mqttPress = nullptr;
|
|
HASensorNumber* mqttLux = nullptr;
|
|
HABinarySensor* mqttRadar = nullptr;
|
|
HASensorNumber mqttRssi("rssi");
|
|
HASwitch mqttTubes("tubes");
|
|
HANumber mqttDayBright("day_brightness");
|
|
HANumber mqttNightBright("night_brightness");
|
|
HASwitch mqttAutoDim("auto_dim");
|
|
HAButton mqttCathodeProtect("cathode_protect");
|
|
#ifdef USE_NEOPIXEL
|
|
HALight mqttBacklight("backlight", HALight::BrightnessFeature | HALight::RGBFeature);
|
|
HASelect mqttLedEffect("led_effect");
|
|
byte mqttLastEffect = 2; //effect restored when the backlight is switched on from HA (rainbow flow by default)
|
|
#endif
|
|
|
|
//Bounded copy of an MQTT payload into a zero-terminated buffer.
|
|
// FIXED: the old onMqttMessage() memcpy'd the payload into a 100-byte stack buffer without a length check or a
|
|
// terminator (possible stack overflow with a long payload).
|
|
static void payloadToString(const uint8_t* payload, uint16_t length, char* buf, size_t bufSize) {
|
|
size_t n = min((size_t)length, bufSize - 1);
|
|
memcpy(buf, payload, n);
|
|
buf[n] = 0;
|
|
}
|
|
|
|
void onMqttMessage(const char* topic, const uint8_t* payload, uint16_t length) {
|
|
float tempTMP,humidTMP;
|
|
char tmp[32];
|
|
|
|
payloadToString(payload, length, tmp, sizeof(tmp));
|
|
DPRINT("New message on topic: "); DPRINT(topic);
|
|
DPRINT(" Data: "); DPRINTLN(tmp);
|
|
|
|
if ((strlen(masterTemperatureTopic)>0) && (strncmp(topic,masterTemperatureTopic,sizeof(masterTemperatureTopic)) ==0)) {
|
|
tempTMP = atof(tmp);
|
|
temperature[MASTERtempPtr] = tempTMP; //overwrite the reserved "master" slot in the shared temperature[] array (see MASTERtempPtr above)
|
|
DPRINT("MASTER clock's temperature:"); DPRINTLN(tempTMP);
|
|
}
|
|
if ((strlen(masterHumidityTopic)>0) && (strncmp(topic,masterHumidityTopic,sizeof(masterHumidityTopic)) ==0)) {
|
|
humidTMP = atof(tmp);
|
|
DPRINT("MASTER clock's humidity:"); DPRINTLN(humidTMP);
|
|
humid[MASTERhumidPtr] = humidTMP; //overwrite the reserved "master" slot in the shared humid[] array (see MASTERhumidPtr above)
|
|
}
|
|
if ((strlen(masterRadarTopic)>0) && (strncmp(topic,masterRadarTopic,sizeof(masterRadarTopic)) ==0)) {
|
|
DPRINT("MASTER radar:"); DPRINTLN(tmp[0]);
|
|
if ((tmp[0] == '0') || (strcmp(tmp, "OFF") == 0)) {
|
|
mqttRadarON = false;
|
|
radarON = mqttRadarON;
|
|
}
|
|
else {
|
|
mqttRadarON = true;
|
|
radarON = mqttRadarON;
|
|
radarLastOn = millis();
|
|
}
|
|
DPRINT("mqttRadarON:"); DPRINTLN(mqttRadarON);
|
|
}
|
|
}
|
|
|
|
void onMqttConnected() {
|
|
DPRINTLN("Connected to the broker!");
|
|
#ifdef USE_MASTER_CLOCK
|
|
DPRINTLN(F("MASTER_CLOCK enabled! Subscribe to following topics:"));
|
|
#ifdef USE_MASTER_TEMP
|
|
if (strlen(masterTemperatureTopic)==0) {
|
|
DPRINTLN("Please define MASTER_TEMPERATURE_TOPIC in clocks.h'");
|
|
}
|
|
else {
|
|
DPRINT(F("Master temperature topic:")); DPRINTLN(masterTemperatureTopic);
|
|
mqtt.subscribe(masterTemperatureTopic);
|
|
}
|
|
#endif
|
|
#ifdef USE_MASTER_HUMID
|
|
if (strlen(masterHumidityTopic)==0) {
|
|
DPRINTLN("Please define MASTER_HUMIDITY_TOPIC in clocks.h'");
|
|
}
|
|
else {
|
|
DPRINT(F("Master humidity topic:")); DPRINTLN(masterHumidityTopic);
|
|
mqtt.subscribe(masterHumidityTopic);
|
|
}
|
|
#endif
|
|
#ifdef USE_MASTER_RADAR
|
|
if (RADAR_PIN>=0) {
|
|
DPRINTLN(F("Local radar enabled! MQTT MASTER radar disabled!"));
|
|
}
|
|
else {
|
|
if (strlen(masterRadarTopic)==0) {
|
|
DPRINTLN("Please define MASTER_RADAR_TOPIC in clocks.h'");
|
|
}
|
|
else {
|
|
DPRINT(F("Master radar topic:")); DPRINTLN(masterRadarTopic);
|
|
mqtt.subscribe(masterRadarTopic);
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
//--- commands from Home Assistant ---------------------------------------------------------------------------------------
|
|
|
|
void mqttRequestSave() {
|
|
mqttSaveRequested = millis();
|
|
if (mqttSaveRequested == 0) mqttSaveRequested = 1;
|
|
}
|
|
|
|
void onTubesCommand(bool state, HASwitch* sender) {
|
|
tubesOn = state;
|
|
DPRINT("MQTT: tubes "); DPRINTLN(state ? "on" : "off");
|
|
sender->setState(state);
|
|
}
|
|
|
|
void onBrightnessCommand(HANumeric number, HANumber* sender) {
|
|
if (!number.isSet()) return;
|
|
int v = constrain((int)number.toInt16(), 0, MAXBRIGHTNESS);
|
|
if (sender == &mqttDayBright) prm.dayBright = v;
|
|
else prm.nightBright = v;
|
|
sender->setState(v);
|
|
mqttRequestSave();
|
|
}
|
|
|
|
void onAutoDimCommand(bool state, HASwitch* sender) {
|
|
prm.enableAutoDim = state;
|
|
autoBrightness = state; //same as the web UI handler: takes effect at once
|
|
sender->setState(state);
|
|
mqttRequestSave();
|
|
}
|
|
|
|
void onCathodeProtectCommand(HAButton* sender) {
|
|
makeCathodeProtect = true; //executed from loop(), like the web UI button
|
|
}
|
|
|
|
#ifdef USE_NEOPIXEL
|
|
//Inverse of Wheel() in z_neopixel.ino: the wheel position whose hue is closest to an RGB colour (saturation and
|
|
//brightness are ignored; grey/white maps to the white position).
|
|
byte rgbToWheel(byte r, byte g, byte b) {
|
|
byte lo = min(r, min(g, b));
|
|
int q;
|
|
if ((max(r, max(g, b)) - lo) < 16) return MQTT_WHITE_INDEX;
|
|
r -= lo; g -= lo; b -= lo;
|
|
if (g == 0) q = (85 * b) / (r + b); //Wheel q 0..84: (255-3k, 0, 3k)
|
|
else if (r == 0) q = 85 + (85 * g) / (g + b); //Wheel q 85..169: (0, 3k, 255-3k)
|
|
else q = 170 + (85 * r) / (r + g); //Wheel q 170..254: (3k, 255-3k, 0)
|
|
q = min(q, 254);
|
|
byte pos = 255 - q; //Wheel() inverts its argument
|
|
if (pos == MQTT_WHITE_INDEX) pos++; //192 is reserved for white
|
|
return pos;
|
|
}
|
|
|
|
HALight::RGBColor wheelToRgb(byte pos) {
|
|
RgbColor c = WheelRaw(pos); //without gamma correction, so it matches what HA sent
|
|
HALight::RGBColor color;
|
|
color.red = c.R; color.green = c.G; color.blue = c.B;
|
|
color.isSet = true;
|
|
return color;
|
|
}
|
|
|
|
void onBacklightStateCommand(bool state, HALight* sender) {
|
|
if (state) {
|
|
if (prm.rgbEffect == 0) prm.rgbEffect = (mqttLastEffect > 0) ? mqttLastEffect : 1;
|
|
}
|
|
else {
|
|
if (prm.rgbEffect > 0) mqttLastEffect = prm.rgbEffect;
|
|
prm.rgbEffect = 0;
|
|
}
|
|
sender->setState(state);
|
|
mqttLedEffect.setState(prm.rgbEffect);
|
|
mqttRequestSave();
|
|
}
|
|
|
|
void onBacklightBrightnessCommand(uint8_t brightness, HALight* sender) {
|
|
prm.rgbBrightness = brightness;
|
|
sender->setBrightness(brightness);
|
|
mqttRequestSave();
|
|
}
|
|
|
|
void onBacklightColorCommand(HALight::RGBColor color, HALight* sender) {
|
|
if (!color.isSet) return;
|
|
prm.rgbFixColor = rgbToWheel(color.red, color.green, color.blue);
|
|
prm.rgbEffect = 1; //a colour from HA means "fixed colour"
|
|
sender->setRGBColor(wheelToRgb(prm.rgbFixColor));
|
|
mqttLedEffect.setState(prm.rgbEffect);
|
|
mqttRequestSave();
|
|
}
|
|
|
|
void onLedEffectCommand(int8_t index, HASelect* sender) {
|
|
if ((index < 0) || (index > 10)) return;
|
|
prm.rgbEffect = index;
|
|
if (index > 0) mqttLastEffect = index;
|
|
sender->setState(index);
|
|
mqttBacklight.setState(index > 0);
|
|
mqttRequestSave();
|
|
}
|
|
#endif
|
|
|
|
void setupMqtt() {
|
|
char mactmp[20];
|
|
|
|
WiFi.macAddress(mac);
|
|
device.setUniqueId(mac, sizeof(mac)); //set device MAC, as unique ID
|
|
device.enableExtendedUniqueIds(); //entity unique IDs = <mac>_<entity>, so several clocks don't clash in HA
|
|
sprintf(mactmp,"%02x%02x%02x%02x%02x%02x",mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);
|
|
|
|
#if defined(MASTER_TEMPERATURE_TOPIC)
|
|
strncpy(masterTemperatureTopic,MASTER_TEMPERATURE_TOPIC,sizeof(masterTemperatureTopic));
|
|
#endif
|
|
#if defined(MASTER_HUMIDITY_TOPIC)
|
|
strncpy(masterHumidityTopic,MASTER_HUMIDITY_TOPIC,sizeof(masterHumidityTopic));
|
|
#endif
|
|
#if defined(MASTER_RADAR_TOPIC)
|
|
strncpy(masterRadarTopic,MASTER_RADAR_TOPIC,sizeof(masterRadarTopic));
|
|
#endif
|
|
|
|
DPRINT("Starting MQTT Client, discovery prefix: "); DPRINT(MQTT_PREFIX); DPRINT(" device: "); DPRINTLN(mactmp);
|
|
mqtt.setDiscoveryPrefix(MQTT_PREFIX);
|
|
device.setName(webName);
|
|
device.setManufacturer("UniClock");
|
|
device.setModel(tubeDriver);
|
|
device.setSoftwareVersion(FW);
|
|
snprintf(mqttConfigUrl, sizeof(mqttConfigUrl), "http://%s/", WiFi.localIP().toString().c_str());
|
|
device.setConfigurationUrl(mqttConfigUrl);
|
|
device.enableSharedAvailability();
|
|
device.enableLastWill();
|
|
|
|
//useTemp/useHumid count the master clock's sensors too, which are added at the end of this function -
|
|
//so as before, a master-only sensor is not republished by this clock
|
|
if (useTemp>0) {
|
|
mqttTemp = new HASensorNumber("temperature", HASensorNumber::PrecisionP1);
|
|
mqttTemp->setName("Temperature");
|
|
mqttTemp->setDeviceClass("temperature");
|
|
mqttTemp->setUnitOfMeasurement("°C");
|
|
}
|
|
if (useHumid>0) {
|
|
mqttHumid = new HASensorNumber("humidity", HASensorNumber::PrecisionP1);
|
|
mqttHumid->setName("Humidity");
|
|
mqttHumid->setDeviceClass("humidity");
|
|
mqttHumid->setUnitOfMeasurement("%");
|
|
}
|
|
if (usePress>0) {
|
|
mqttPress = new HASensorNumber("pressure", HASensorNumber::PrecisionP1);
|
|
mqttPress->setName("Air pressure");
|
|
mqttPress->setDeviceClass("pressure");
|
|
mqttPress->setUnitOfMeasurement("hPa");
|
|
}
|
|
if (useLux>0) {
|
|
mqttLux = new HASensorNumber("lux");
|
|
mqttLux->setName("Light");
|
|
mqttLux->setDeviceClass("illuminance");
|
|
mqttLux->setUnitOfMeasurement("lx");
|
|
}
|
|
#if RADAR_PIN>=0
|
|
mqttRadar = new HABinarySensor("radar");
|
|
mqttRadar->setName("Radar");
|
|
mqttRadar->setDeviceClass("occupancy");
|
|
#endif
|
|
mqttRssi.setName("WiFi signal");
|
|
mqttRssi.setDeviceClass("signal_strength");
|
|
mqttRssi.setUnitOfMeasurement("dBm");
|
|
|
|
mqttTubes.setName("Tubes");
|
|
mqttTubes.setIcon("mdi:numeric");
|
|
mqttTubes.onCommand(onTubesCommand);
|
|
|
|
mqttDayBright.setName("Day brightness");
|
|
mqttNightBright.setName("Night brightness");
|
|
for (HANumber* n : {&mqttDayBright, &mqttNightBright}) {
|
|
n->setIcon("mdi:brightness-6");
|
|
n->setMin(0);
|
|
n->setMax(MAXBRIGHTNESS);
|
|
n->setMode(HANumber::ModeSlider);
|
|
n->onCommand(onBrightnessCommand);
|
|
}
|
|
|
|
mqttAutoDim.setName("Auto dim");
|
|
mqttAutoDim.setIcon("mdi:brightness-auto");
|
|
mqttAutoDim.onCommand(onAutoDimCommand);
|
|
|
|
mqttCathodeProtect.setName("Cathode protect");
|
|
mqttCathodeProtect.setIcon("mdi:autorenew");
|
|
mqttCathodeProtect.onCommand(onCathodeProtectCommand);
|
|
|
|
#ifdef USE_NEOPIXEL
|
|
mqttBacklight.setName("Backlight");
|
|
mqttBacklight.onStateCommand(onBacklightStateCommand);
|
|
mqttBacklight.onBrightnessCommand(onBacklightBrightnessCommand);
|
|
mqttBacklight.onRGBColorCommand(onBacklightColorCommand);
|
|
if (prm.rgbEffect > 0) mqttLastEffect = prm.rgbEffect;
|
|
|
|
mqttLedEffect.setName("LED effect");
|
|
mqttLedEffect.setIcon("mdi:led-strip-variant");
|
|
//order = prm.rgbEffect values, see doAnimationMakuna() in z_neopixel.ino
|
|
mqttLedEffect.setOptions("Off;Fixed colour;Rainbow flow;Rainbow step;Colour dimmer;Colour stepper;"
|
|
"Stepflow table;Stepflow random;Stepflow random pixels;Stepflow random all;KITT");
|
|
mqttLedEffect.onCommand(onLedEffectCommand);
|
|
#endif
|
|
|
|
mqtt.onMessage(onMqttMessage);
|
|
mqtt.onConnected(onMqttConnected);
|
|
|
|
IPAddress tmp;
|
|
tmp.fromString(String(prm.mqttBrokerAddr));
|
|
if (strlen(prm.mqttBrokerUser)==0)
|
|
mqtt.begin(tmp);
|
|
else
|
|
mqtt.begin(tmp, prm.mqttBrokerUser, prm.mqttBrokerPsw);
|
|
|
|
#ifdef USE_MASTER_CLOCK
|
|
DPRINTLN("MQTT MASTER_CLOCK enabled!");
|
|
DPRINT("MASTER_TEMPERATURE_TOPIC:"); DPRINTLN(masterTemperatureTopic);
|
|
DPRINT("MASTER_HUMIDITY_TOPIC:"); DPRINTLN(masterHumidityTopic);
|
|
DPRINT("MASTER_RADAR_TOPIC:"); DPRINTLN(masterRadarTopic);
|
|
#ifdef USE_MASTER_TEMP
|
|
DPRINTLN(" - MQTT MASTER_TEMP sensor added!");
|
|
MASTERtempPtr = useTemp; //remember my ID-s
|
|
useTemp++; //increase the number of sensors
|
|
#endif
|
|
#ifdef USE_MASTER_HUMID
|
|
DPRINTLN(" - MQTT MASTER_HUMID sensor added!");
|
|
MASTERhumidPtr = useHumid;
|
|
useHumid++;
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
//Report the current settings to HA. The library only publishes values that changed, so this is cheap; it keeps
|
|
//HA in sync with changes made on the clock's web page.
|
|
void mqttReportState() {
|
|
mqttTubes.setState(tubesOn);
|
|
mqttDayBright.setState((int16_t)prm.dayBright);
|
|
mqttNightBright.setState((int16_t)prm.nightBright);
|
|
mqttAutoDim.setState(prm.enableAutoDim);
|
|
#ifdef USE_NEOPIXEL
|
|
mqttBacklight.setState(prm.rgbEffect > 0);
|
|
mqttBacklight.setBrightness(prm.rgbBrightness);
|
|
mqttBacklight.setRGBColor(wheelToRgb(prm.rgbFixColor));
|
|
mqttLedEffect.setState(prm.rgbEffect);
|
|
#endif
|
|
}
|
|
|
|
void mqttSend() {
|
|
static unsigned long lastRun = 0;
|
|
static unsigned long lastReport = 0;
|
|
static bool wasConnected = false;
|
|
|
|
mqtt.loop();
|
|
|
|
if (mqttSaveRequested && ((millis() - mqttSaveRequested) > MQTT_SAVE_DELAY)) {
|
|
mqttSaveRequested = 0;
|
|
DPRINTLN("MQTT: saving settings");
|
|
saveEEPROM();
|
|
}
|
|
|
|
if (!mqtt.isConnected()) {
|
|
wasConnected = false;
|
|
return;
|
|
}
|
|
if (!wasConnected) { //(re)connected: force the first sensor refresh now
|
|
wasConnected = true;
|
|
lastRun = millis() - 1000ul * max((int)prm.mqttBrokerRefresh, MQTT_MIN_REFRESH);
|
|
}
|
|
|
|
if ((millis() - lastReport) > 1000) {
|
|
lastReport = millis();
|
|
mqttReportState();
|
|
}
|
|
|
|
if ((millis() - lastRun) < 1000ul * max((int)prm.mqttBrokerRefresh, MQTT_MIN_REFRESH)) return;
|
|
lastRun = millis();
|
|
|
|
DPRINT("MQTT send:");
|
|
if (mqttTemp) {mqttTemp->setValue(temperature[0]+ prm.corrT0); DPRINT(temperature[0]+ prm.corrT0); DPRINT(", ");}
|
|
if (mqttHumid) {mqttHumid->setValue(humid[0]+ prm.corrH0); DPRINT(humid[0]+ prm.corrH0); DPRINT(", ");}
|
|
if (mqttPress) {mqttPress->setValue(pressur[0]); DPRINT(pressur[0]); DPRINT(", ");}
|
|
if (mqttLux) {mqttLux->setValue((int32_t)lx); DPRINT(lx); DPRINT(", ");}
|
|
if (mqttRadar) {mqttRadar->setState(radarON); DPRINT(radarON);}
|
|
mqttRssi.setValue((int32_t)WiFi.RSSI());
|
|
DPRINTLN(" ");
|
|
}
|
|
|
|
#else
|
|
void mqttSend() {}
|
|
#endif
|