Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion usermods/PIR_sensor_switch/PIR_sensor_switch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,9 @@ void PIRsensorSwitch::publishHomeAssistantAutodiscovery()
device[F("mf")] = F(WLED_BRAND);
device[F("mdl")] = F(WLED_PRODUCT_NAME);
device[F("sw")] = versionString;

JsonArray connections = device[F("connections")].createNestedArray();
connections.add(F("mac"));
connections.add(WiFi.macAddress());
sprintf_P(buf, PSTR("homeassistant/binary_sensor/%s/config"), uid);
DEBUG_PRINTLN(buf);
size_t payload_size = serializeJson(doc, json_str);
Expand Down
37 changes: 37 additions & 0 deletions usermods/photoresistor_sensor_mqtt_v2/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Photoresister sensor with MQTT ## based on LDR_Dusk_Dawn_v2 usermod from [@jeffwdh](https://github.com/jeffwdh)
This usermod will obtain readings from a Light Dependent Resistor (LDR). This is useful for exterior lighting situations where you want the lights to only be on when it is dark out. but this mod is designed for more hass application. it will publish auto discovery message to hass mqtt and attach the light sensor to the wled integration automatically
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Clarify and Correct the Introduction
The header and opening paragraph contain a few typographical and grammatical issues. For example, "Photoresister" should be corrected to "Photoresistor" to match the file name, and the wording—especially around "more hass application" and "auto discovery message"—can be improved for clarity and formality. Consider revising the text as follows:

"Photoresistor sensor with MQTT – based on the LDR_Dusk_Dawn_v2 usermod from @jeffwdh"

This usermod obtains readings from a Light Dependent Resistor (LDR), which is useful for exterior lighting conditions where the lights should only be on when it is dark. However, this mod is designed primarily for Home Assistant integration: it publishes auto-discovery messages via MQTT to automatically attach the light sensor to the WLED integration.

This will address the issues flagged by LanguageTool and improve overall clarity.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~2-~2: You might be missing the article “an” here.
Context: ... more hass application. it will publish auto discovery message to hass mqtt and atta...

(AI_EN_LECTOR_MISSING_DETERMINER_AN)


# Installation
Add "photoresistor_sensor_mqtt_v2" to your platformio.ini environment's custom_usermods and build.

Example:
```
[env:usermod_LDR_Dusk_Dawn_esp32dev]
extends = env:esp32dev
custom_usermods = ${env:esp32dev.custom_usermods}
photoresistor_sensor_mqtt_v2 # Enable LDR Dusk Dawn Usermod
```

# Usermod Settings
Setting | Description | Default
--- | --- | ---
Enabled | Enable/Disable the LDR functionality. | Disabled
LDR Pin | The analog capable pin your LDR is connected to. | A0
LDR update interval | update interval to read the analog pin ( in ms ) | 3000
LDR inverted | invert readings based on your own hardware setup ( invert mapping analog to digital value to 0V = 100% or 3.3V = 100% ) | false
change threshould | the minimum limit to detect change and publish the value (in % ; float ; ex 0.8 ) . | 1.0

## Author
[@jeffrommo911wdh](https://github.com/rommo911)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Username needs fixing.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'll put it in a seperate PR . its very useful for hass integration

based on :
[@jeffwdh](https://github.com/jeffwdh)
[email protected]

Enables attaching a photoresistor sensor like the KY-018 and publishing the readings as a percentage, via MQTT. The frequency of MQTT messages is user definable.
A threshold value can be set so significant changes in the readings are published immediately vice waiting for the next update. This was found to be a good compromise between excessive MQTT traffic and delayed updates.

I also found it useful to limit the frequency of analog pin reads, otherwise the board hangs.

This usermod has only been tested with the KY-018 sensor though it should work for any other analog pin sensor.
Note: this does not control the LED strip directly, it only publishes MQTT readings for use with other integrations like Home Assistant.

3 changes: 3 additions & 0 deletions usermods/photoresistor_sensor_mqtt_v2/library.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"name:": "photoresistor_sensor_mqtt_v2"
}
204 changes: 204 additions & 0 deletions usermods/photoresistor_sensor_mqtt_v2/photoresistor_sensor_mqtt_v2.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
#include "wled.h"

class photoresistor_sensor_mqtt_v2 : public Usermod
{
private:
unsigned long update_interval = 3000;
float change_threshold = 1;
static const char MQTT_TOPIC[];
static const char _name[];
const bool HomeAssistantDiscovery = true; // is HA discovery turned on by default
int ldrPin = A0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use actual GPIO number and not Arduino pin monikers.

unsigned long lastTime = 0;
unsigned int lightValue = 0;
float lightPercentage = 0;
float lastPercentage = 0;
bool hassDiscoverySent = false;
bool ldrEnabled = true;
bool inverted = false;
bool initDone = false;
String topic_buf;

public:
photoresistor_sensor_mqtt_v2() {}

void setup()
{
// register ldrPin
if ((ldrPin >= 0) && ldrEnabled)
{
if (!PinManager::allocatePin(ldrPin, false, PinOwner::UM_PHOTO_RESISTOR_MQTT))
{
ldrEnabled = false; // pin already in use -> disable usermod
}
else
{
pinMode(ldrPin, INPUT); // alloc success -> configure pin for input
}
}
else
{
ldrEnabled = false; // invalid pin -> disable usermod
}
initDone = true;
}

void connected()
{
if (WLED_MQTT_CONNECTED && HomeAssistantDiscovery)
{
publishDiscovery();
}
}

void loop()
{
if (initDone && ldrEnabled && WLED_MQTT_CONNECTED)
{
bool force_update = (millis() - lastTime) > (update_interval * 100); // to keep the mqtt alive if the light is not changing
bool regular_update = (millis() - lastTime) > update_interval;
if (regular_update || force_update)
{
lightValue = analogRead(ldrPin);
#ifdef ESP32
const float mapping = 4096.0; // ESP32 ADC resolution is 12 bit, so 4096 values
#else
const float mapping = 1024.0; // ESP8266 ADC resolution is 10 bit, so 1024 values
#endif
if (inverted)
{
lightPercentage = 100.0 - ((float)lightValue * -1 + mapping) / (float)mapping * 100;
}
else
{
lightPercentage = ((float)lightValue * -1 + mapping) / (float)mapping * 100;
}

if (abs(lightPercentage - lastPercentage) > change_threshold || force_update)
{
if (WLED_MQTT_CONNECTED)
{
publishMqtt(lightPercentage);
}
lastTime = millis();
lastPercentage = lightPercentage;
// debug
char buf[64];
sprintf_P(buf, PSTR("LDR: %d (%d)"), (int)lightPercentage, lightValue);
DEBUG_PRINTLN(buf);
}
}
}
}

void addToConfig(JsonObject &root)
{
JsonObject top = root.createNestedObject(FPSTR(_name));
top["Enabled"] = ldrEnabled;
top["LDR Pin"] = ldrPin;
top["LDR update interval"] = update_interval;
top["LDR inverted"] = inverted;
top["change threshould"] = change_threshold;
}

bool readFromConfig(JsonObject &root)
{
int8_t oldLdrPin = ldrPin;
JsonObject top = root[FPSTR(_name)];
bool configComplete = !top.isNull();
configComplete &= getJsonValue(top["Enabled"], ldrEnabled);
configComplete &= getJsonValue(top["LDR Pin"], ldrPin);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even though it is (currently) supported, I would avoid spaces in JSON key names.

configComplete &= getJsonValue(top["LDR update interval"], update_interval);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are cfg.json configuration item key names. They need not be descriptive. Use addInfo() to add description.

configComplete &= getJsonValue(top["LDR inverted"], inverted);
configComplete &= getJsonValue(top["change threshould"], change_threshold);
// pin changed - un-register previous pin, register new pin
PinManager::deallocatePin(oldLdrPin, PinOwner::UM_PHOTO_RESISTOR_MQTT);
if (ldrEnabled && ldrPin > 0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is a 0 invalid entry?

{
setup(); // setup again
}
return configComplete;
}

void addToJsonInfo(JsonObject &root)
{
// If "u" object does not exist yet we need to create it
JsonObject user = root["u"];
if (user.isNull())
user = root.createNestedObject("u");

JsonArray LDR_Enabled = user.createNestedArray("LDR enabled");
LDR_Enabled.add(ldrEnabled);
if (!ldrEnabled)
return; // do not add more if usermod is disabled

JsonArray LDR_Reading = user.createNestedArray("LDR reading");
LDR_Reading.add(lightPercentage);

JsonArray LDR_interval = user.createNestedArray("LDR interval");
LDR_interval.add(update_interval);

JsonArray LDR_change_threshold = user.createNestedArray("change threshould");
LDR_change_threshold.add(change_threshold);
}

uint16_t getId()
{
return USERMOD_PHOTORESISTOR_MQTT_V2;
}

void publishMqtt(float state)
{
if (WLED_MQTT_CONNECTED)
{
topic_buf = mqttDeviceTopic;
topic_buf += MQTT_TOPIC;
if (!hassDiscoverySent && HomeAssistantDiscovery)
{
publishDiscovery();
}
mqtt->publish(topic_buf.c_str(), 0, true, String(state).c_str());
}
}

void publishDiscovery()
{
StaticJsonDocument<600> doc;
String uid = escapedMac.c_str();
doc[F("name")] = F("Light Sensor");
doc[F("stat_t")] = topic_buf.c_str();
uid += F("_ldr");
doc[F("uniq_id")] = uid;
doc[F("dev_cla")] = F("illuminance");
doc[F("unit_of_meas")] = F("lx");
doc[F("val_tpl")] = F("{{ value }}");

JsonObject device = doc.createNestedObject(F("device")); // attach the sensor to the same device
device[F("name")] = serverDescription;
device[F("ids")] = serverDescription;
device[F("mf")] = F(WLED_BRAND);
device[F("mdl")] = F(WLED_PRODUCT_NAME);
device[F("sw")] = versionString;
#ifdef ESP32
device[F("hw_version")] = F("esp32");
#else
device[F("hw_version")] = F("esp8266");
#endif
JsonArray connections = device[F("connections")].createNestedArray();
connections.add(F("mac"));
connections.add(WiFi.macAddress());

String discovery_topic = F("homeassistant/sensor/");
discovery_topic += uid;
discovery_topic += F("/ldr/config");
char json_str[600];
size_t payload_size = serializeJson(doc, json_str);
mqtt->publish(discovery_topic.c_str(), 0, true, json_str, payload_size);
hassDiscoverySent = true;
}
};
const char photoresistor_sensor_mqtt_v2::_name[] PROGMEM = "photoresistor_sensor_mqtt_v2";
const char photoresistor_sensor_mqtt_v2::MQTT_TOPIC[] PROGMEM = "/ldr";

static photoresistor_sensor_mqtt_v2 photoresistor_sensor_mqtt_v2_instance;
REGISTER_USERMOD(photoresistor_sensor_mqtt_v2_instance);
2 changes: 1 addition & 1 deletion wled00/const.h
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@
#define USERMOD_ID_DEEP_SLEEP 55 //Usermod "usermod_deep_sleep.h"
#define USERMOD_ID_RF433 56 //Usermod "usermod_v2_RF433.h"
#define USERMOD_ID_BRIGHTNESS_FOLLOW_SUN 57 //Usermod "usermod_v2_brightness_follow_sun.h"

#define USERMOD_PHOTORESISTOR_MQTT_V2 58 //Usermod "usermod_photoresistor_sensor_mqtt_v2.h"
//Access point behavior
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot
#define AP_BEHAVIOR_NO_CONN 1 //Open when no connection (either after boot or if connection is lost)
Expand Down
3 changes: 2 additions & 1 deletion wled00/pin_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ enum struct PinOwner : uint8_t {
UM_LDR_DUSK_DAWN = USERMOD_ID_LDR_DUSK_DAWN, // 0x2B // Usermod "usermod_LDR_Dusk_Dawn_v2.h"
UM_MAX17048 = USERMOD_ID_MAX17048, // 0x2F // Usermod "usermod_max17048.h"
UM_BME68X = USERMOD_ID_BME68X, // 0x31 // Usermod "usermod_bme68x.h -- Uses "standard" HW_I2C pins
UM_PIXELS_DICE_TRAY = USERMOD_ID_PIXELS_DICE_TRAY // 0x35 // Usermod "pixels_dice_tray.h" -- Needs compile time specified 6 pins for display including SPI.
UM_PIXELS_DICE_TRAY = USERMOD_ID_PIXELS_DICE_TRAY, // 0x35 // Usermod "pixels_dice_tray.h" -- Needs compile time specified 6 pins for display including SPI.
UM_PHOTO_RESISTOR_MQTT = USERMOD_PHOTORESISTOR_MQTT_V2 // 0x3A // Usermod "photoresistor_sensor_mqtt_v2.cpp" -- Uses default pin (ldrPin = A0), but could be easily updated with pinManager from ui
};
static_assert(0u == static_cast<uint8_t>(PinOwner::None), "PinOwner::None must be zero, so default array initialization works as expected");

Expand Down