Porównaj commity

...

9 Commity

Autor SHA1 Wiadomość Data
Daniel Breitlauch bfb455c993
Merge 6b85ca8f77 into 197f47befe 2024-04-21 16:36:18 +02:00
Blaž Kristan 197f47befe
Merge pull request #3905 from w00000dy/main
Set stale lable to 'stale' and increase operations-per-run in stale.yml
2024-04-16 20:31:16 +02:00
Woody 6272969983
Set stale-pr-label & stale-issue-label to 'stale' in stale.yml
Hopefully this fixes the error messages that were thrown the last time the action was executed
2024-04-16 15:07:12 +02:00
Woody b2e68db380
Increase operations-per-run in stale.yml again 2024-04-15 22:56:38 +02:00
Daniel Breitlauch 6b85ca8f77 same invite time up and down 2024-03-14 16:21:20 +01:00
Daniel Breitlauch df92faab47 fix setting pin mode 2024-03-14 15:46:05 +01:00
Daniel Breitlauch 48880d23cb add mqtt ha sensors which detect the direction a person went 2024-03-14 15:46:05 +01:00
Daniel Breitlauch 15675c89c9 fix shuting down if invitation not taken 2024-03-14 15:46:05 +01:00
Daniel Breitlauch 5f290b7282 Add Staircase usermod with position measurements 2024-03-14 15:46:05 +01:00
7 zmienionych plików z 738 dodań i 5 usunięć

Wyświetl plik

@ -12,10 +12,12 @@ jobs:
with:
days-before-stale: 120
days-before-close: 7
stale-issue-label: 'stale'
stale-pr-label: 'stale'
exempt-issue-labels: 'pinned,keep,enhancement,confirmed'
exempt-pr-labels: 'pinned,keep,enhancement,confirmed'
exempt-all-milestones: true
operations-per-run: 150
operations-per-run: 1000
stale-issue-message: >
Hey! This issue has been open for quite some time without any new comments now.
It will be closed automatically in a week if no further activity occurs.

6
.vscode/tasks.json vendored
Wyświetl plik

@ -9,8 +9,8 @@
],
"dependsOrder": "sequence",
"problemMatcher": [
"$platformio",
],
"$platformio"
]
},
{
"type": "PlatformIO",
@ -18,7 +18,7 @@
"task": "Build",
"group": {
"kind": "build",
"isDefault": true,
"isDefault": true
},
"problemMatcher": [
"$platformio"

Wyświetl plik

@ -0,0 +1,643 @@
/*
* Usermod for detecting people entering/leaving a staircase and switching the
* every stair depending on distance of the person.
*
* Edit the Distance_Staircase_config.h file to compile this usermod for your
* specific configuration.
*
* See the accompanying README.md file for more info.
*/
#pragma once
#include "wled.h"
class Distance_Staircase : public Usermod {
private:
class Timer {
unsigned long delay_ms;
unsigned long lastTime = 0;
public:
explicit Timer(unsigned long delay_ms): delay_ms{delay_ms} {}
void reset() {
lastTime = millis();
}
bool wouldBlock() {
return ((millis() - lastTime) < delay_ms);
}
bool isEarly() {
if (wouldBlock()) {
return true;
}
reset();
return false;
}
};
enum WalkDirection {
Up, Down
};
enum AnimationState : uint8_t {
None, Enter, FollowDistance, Finish, CoolDown, Reset
};
struct State {
private:
static const long on_time_ms = 20000; // The time for the light to stay on
static const long invite_time_ms = 5000; // The time for the light to stay on without movement
long lastChange = millis();
AnimationState _animation = None;
public:
WalkDirection direction = Up;
State() {}
State(AnimationState ani, WalkDirection dir): _animation{ani}, direction{dir} {
lastChange = millis();
}
const AnimationState& animation() {
return _animation;
}
void set(AnimationState ani) {
_animation = ani;
lastChange = millis();
}
bool inviteTimeOver() {
return (millis() - lastChange) > invite_time_ms;
}
bool onTimeOver() {
return (millis() - lastChange) > on_time_ms;
}
};
template<int SIZE = 6>
class SmoothMeasure {
int lastDistancesMeasuredPosition = 0;
int lastDistancesMeasured[SIZE] = {0};
int init = 0;
public:
int value = 0, lastValue = 0;
SmoothMeasure() {}
bool hasChanged() {
return value > 0 && value != lastValue;
}
void reset() {
init = 0;
lastDistancesMeasuredPosition = 0;
}
void feed(int cm) {
lastDistancesMeasured[lastDistancesMeasuredPosition] = cm;
lastDistancesMeasuredPosition = (lastDistancesMeasuredPosition + 1) % SIZE;
if (init != SIZE) {
init++;
}
int min = std::numeric_limits<int>::max();
int max = std::numeric_limits<int>::min();
int sum = 0;
for (auto measure : lastDistancesMeasured) {
min = MIN(min, measure);
max = MAX(max, measure);
sum += measure;
}
sum -= min + max;
lastValue = value;
value = sum / (SIZE - 2);
}
};
State state;
Timer animationTimer = Timer(500);
Timer finishSwipeTimer = Timer(250);
Timer scanTimer = Timer(50);
Timer coolDownTimer = Timer(3000);
/* configuration (available in API and stored in flash) */
bool enabled = false; // Enable this usermod
int8_t triggerPin = -1; // disabled
int8_t echoPin = -1; // disabled
int8_t topPIRPin = -1; // disabled
int8_t bottomPIRPin = -1; // disabled
int endOfStairsDistance = 145;
/* runtime variables */
bool initDone = false;
bool HAautodiscovery = true;
// segment id between onIndex and offIndex are on.
// control the swipe by setting/moving these indices around.
// onIndex must be less than or equal to offIndex
byte onIndex = 0;
byte offIndex = 0;
// The maximum number of configured segments.
// Dynamically updated based on user configuration.
byte maxSegmentId = 1;
byte minSegmentId = 0;
bool topSensorState = false;
bool bottomSensorState = false;
SmoothMeasure<3> distanceState;
WalkDirection lastActiveSensor = Down;
// strings to reduce flash memory usage (used more than twice)
static const char _name[];
static const char _enabled[];
static const char _onTime[];
static const char _endOfStairsDistance[];
static const char _HAautodiscovery[];
static const char _topPIRPin[];
static const char _bottomPIRPin[];
static const char _sonarTriggerPin[];
static const char _sonarEchoPin[];
enum MotionType {
Bottom, Top, WentUp, WentDown
};
const char* motionTypeName(MotionType type) {
switch (type) {
case Bottom: return "Bottom";
case Top: return "Top";
case WentUp: return "WentUp";
case WentDown: return "WentDown";
}
return "unknown";
}
void publishMqtt(MotionType type, bool state) {
#ifndef WLED_DISABLE_MQTT
//Check if MQTT Connected, otherwise it will crash the 8266
if (WLED_MQTT_CONNECTED){
char subuf[64];
sprintf_P(subuf, PSTR("%s/motion/%s"), mqttDeviceTopic, motionTypeName(type));
mqtt->publish(subuf, 0, false, state ? "on" : "off");
}
#endif
}
void publishDistanceMqtt() {
#ifndef WLED_DISABLE_MQTT
//Check if MQTT Connected, otherwise it will crash the 8266
if (WLED_MQTT_CONNECTED){
char subuf[64];
char dist[16];
sprintf_P(subuf, PSTR("%s/distance/0"), mqttDeviceTopic);
sprintf_P(dist, (PGM_P)F("%03d"), distanceState.value);
mqtt->publish(subuf, 0, true, dist);
}
#endif
}
void publichHomeAssistantAutodiscoveryMotionSensor(MotionType type) {
StaticJsonDocument<600> doc;
char uid[24], json_str[1024], buf[128];
const char* name = motionTypeName(type);
sprintf_P(buf, PSTR("%s %s Motion"), serverDescription, name); //max length: 33 + 7 = 40
doc[F("name")] = buf;
sprintf_P(buf, PSTR("%s/motion/%s"), mqttDeviceTopic, name); //max length: 33 + 7 = 40
doc[F("stat_t")] = buf;
doc[F("pl_on")] = "on";
doc[F("pl_off")] = "off";
sprintf_P(uid, PSTR("%s_%s_motion"), escapedMac.c_str(), name);
doc[F("uniq_id")] = uid;
doc[F("dev_cla")] = F("motion");
JsonObject device = doc.createNestedObject(F("device")); // attach the sensor to the same device
device[F("name")] = serverDescription;
device[F("ids")] = String(F("wled-sensor-")) + mqttClientID;
device[F("mf")] = "WLED";
device[F("mdl")] = F("FOSS");
device[F("sw")] = versionString;
sprintf_P(buf, PSTR("homeassistant/binary_sensor/%s/config"), uid);
DEBUG_PRINTLN(buf);
size_t payload_size = serializeJson(doc, json_str);
DEBUG_PRINTLN(json_str);
mqtt->publish(buf, 0, true, json_str, payload_size); // do we really need to retain?
}
void publichHomeAssistantAutodiscoveryDistanceSensor() {
StaticJsonDocument<600> doc;
char uid[24], json_str[1024], buf[128];
sprintf_P(buf, PSTR("%s Distance"), serverDescription); //max length: 33 + 7 = 40
doc[F("name")] = buf;
sprintf_P(buf, PSTR("%s/distance/0"), mqttDeviceTopic); //max length: 33 + 7 = 40
doc[F("stat_t")] = buf;
sprintf_P(uid, PSTR("%s_distance"), escapedMac.c_str());
doc[F("uniq_id")] = uid;
doc[F("dev_cla")] = F("distance");
doc[F("unit_of_measurement")] = F("cm");
JsonObject device = doc.createNestedObject(F("device")); // attach the sensor to the same device
device[F("name")] = serverDescription;
device[F("ids")] = String(F("wled-sensor-")) + mqttClientID;
device[F("mf")] = "WLED";
device[F("mdl")] = F("FOSS");
device[F("sw")] = versionString;
sprintf_P(buf, PSTR("homeassistant/sensor/%s/config"), uid);
DEBUG_PRINTLN(buf);
size_t payload_size = serializeJson(doc, json_str);
DEBUG_PRINTLN(json_str);
mqtt->publish(buf, 0, true, json_str, payload_size); // do we really need to retain?
}
void onMqttConnect(bool sessionPresent) {
#ifndef WLED_DISABLE_MQTT
if (HAautodiscovery) {
publichHomeAssistantAutodiscoveryMotionSensor(Top);
publichHomeAssistantAutodiscoveryMotionSensor(Bottom);
publichHomeAssistantAutodiscoveryMotionSensor(WentUp);
publichHomeAssistantAutodiscoveryMotionSensor(WentDown);
publichHomeAssistantAutodiscoveryDistanceSensor();
}
#endif
}
void updateSegments() {
for (int i = minSegmentId; i <= maxSegmentId; i++) {
Segment &seg = strip.getSegment(i);
if (!seg.isActive()) {
continue; // skip gaps
}
if (onIndex <= i && i < offIndex) {
seg.setOption(SEG_OPTION_ON, true);
} else {
seg.setOption(SEG_OPTION_ON, false);
}
}
strip.trigger(); // force strip refresh
stateChanged = true; // inform external devices/UI of change
colorUpdated(CALL_MODE_DIRECT_CHANGE);
}
int ultrasoundRead(int8_t signalPin, int8_t echoPin) {
if (signalPin<0 || echoPin<0) return false;
digitalWrite(signalPin, LOW);
delayMicroseconds(2);
digitalWrite(signalPin, HIGH);
delayMicroseconds(10);
digitalWrite(signalPin, LOW);
int duration = pulseIn(echoPin, HIGH, 100000);
int cm = (duration / 2) / 29.1; // Divide by 29.1 or multiply by 0.0343
if (cm < 1 || cm > 400) {
return -1;
}
return cm;
}
void checkSensors() {
if (scanTimer.isEarly()) {
return;
}
int topMovement = digitalRead(topPIRPin);
if (topMovement != topSensorState) {
topSensorState = topMovement;
publishMqtt(Top, topSensorState);
if (topMovement) {
lastActiveSensor = Up;
}
}
int bottomMovement = digitalRead(bottomPIRPin);
if (bottomMovement != bottomSensorState) {
bottomSensorState = bottomMovement;
publishMqtt(Bottom, bottomSensorState);
if (bottomMovement) {
lastActiveSensor = Down;
}
}
if (state.animation() != None) {
int distance = ultrasoundRead(triggerPin, echoPin);
distanceState.feed(distance);
if (distanceState.hasChanged()) {
publishDistanceMqtt();
}
}
}
void animateNoneState() {
if (topSensorState || bottomSensorState) {
state = State(Enter, topSensorState? Down : Up);
if (state.direction == Up) {
onIndex = maxSegmentId - 1;
offIndex = maxSegmentId;
} else {
onIndex = minSegmentId;
offIndex = minSegmentId + 2;
}
}
}
void animateEnterState() {
if (state.inviteTimeOver() && !bottomSensorState && !topSensorState) {
state.set(Reset);
}
if (0 < distanceState.value && distanceState.value < endOfStairsDistance) {
state.set(FollowDistance);
}
}
void animateFollowDistanceState() {
if (animationTimer.isEarly()) {
return;
}
if ((lastActiveSensor == state.direction && distanceState.value > endOfStairsDistance) || // Person went through
(state.onTimeOver() && !bottomSensorState && !topSensorState))
{
state.set(Finish);
}
if (state.direction == Up) {
onIndex = MAX(minSegmentId, distanceState.value / (endOfStairsDistance / strip.getSegmentsNum()) - 4);
} else {
offIndex = MIN(maxSegmentId + 1, distanceState.value / (endOfStairsDistance / strip.getSegmentsNum()) + 3);
}
}
void animateFinishState() {
if (finishSwipeTimer.isEarly()) {
return;
}
if (state.direction == Up) {
offIndex--;
onIndex = 0;
} else {
onIndex++;
}
if (onIndex == offIndex) {
if (state.direction == Up) {
publishMqtt(WentUp, true);
} else {
publishMqtt(WentDown, true);
}
coolDownTimer.reset();
state.set(CoolDown);
}
}
void animate() {
byte oldOn = onIndex;
byte oldOff = offIndex;
switch (state.animation()) {
case None:
animateNoneState();
break;
case Enter:
animateEnterState();
break;
case FollowDistance:
animateFollowDistanceState();
break;
case Finish:
animateFinishState();
break;
case CoolDown:
if (!coolDownTimer.isEarly()) {
publishMqtt(WentUp, false);
publishMqtt(WentDown, false);
state.set(Reset);
}
break;
case Reset:
distanceState.reset();
onIndex = 0;
offIndex = 0;
state.set(None);
}
if (oldOn != onIndex || oldOff != offIndex) {
updateSegments();
}
}
void enable(bool enable) {
manageSegments();
updateSegments();
if (!enable) {
state.set(Reset);
} else {
pinMode(topPIRPin, INPUT_PULLUP);
pinMode(bottomPIRPin, INPUT_PULLUP);
pinMode(triggerPin, OUTPUT);
pinMode(echoPin, INPUT);
}
enabled = enable;
}
uint8_t getFirstActiveSegmentId(void) {
for (size_t i = 0; i < strip.getSegmentsNum(); i++) {
if (strip.getSegment(i).isActive()) return i;
}
return 0;
}
void manageSegments() {
minSegmentId = getFirstActiveSegmentId();
maxSegmentId = strip.getLastActiveSegmentId();
}
public:
void setup() {
// standardize invalid pin numbers to -1
if (triggerPin < 0) triggerPin = -1;
if (echoPin < 0) echoPin = -1;
if (topPIRPin < 0) topPIRPin = -1;
if (bottomPIRPin < 0) bottomPIRPin = -1;
// allocate pins
PinManagerPinType pins[4] = {
{ triggerPin, true },
{ topPIRPin, false },
{ bottomPIRPin, false },
{ echoPin, false }
};
// NOTE: this *WILL* return TRUE if all the pins are set to -1.
// this is *BY DESIGN*.
if (!pinManager.allocateMultiplePins(pins, 4, PinOwner::UM_DistanceStaircase)) {
triggerPin = -1;
echoPin = -1;
topPIRPin = -1;
bottomPIRPin = -1;
enabled = false;
}
enable(enabled);
initDone = true;
}
void loop() {
if (!enabled || strip.isUpdating()) return;
manageSegments();
checkSensors();
animate();
}
uint16_t getId() { return USERMOD_ID_DISTANCE_STAIRCASE; }
void addToJsonState(JsonObject& root) {
JsonObject staircase = root[FPSTR(_name)];
if (staircase.isNull()) {
staircase = root.createNestedObject(FPSTR(_name));
}
staircase[F("top-sensor")] = topSensorState;
staircase[F("bottom-sensor")] = bottomSensorState;
}
/*
* Reads configuration settings from the json API.
* See void addToJsonState(JsonObject& root)
*/
void readFromJsonState(JsonObject& root) {
if (!initDone) {
return; // prevent crash on boot applyPreset()
}
bool en = enabled;
JsonObject staircase = root[FPSTR(_name)];
if (!staircase.isNull()) {
if (staircase[FPSTR(_enabled)].is<bool>()) {
en = staircase[FPSTR(_enabled)].as<bool>();
} else {
String str = staircase[FPSTR(_enabled)]; // checkbox -> off or on
en = (bool)(str != "off"); // off is guaranteed to be present
}
if (en != enabled) {
enable(en);
}
}
}
/*
* Writes the configuration to internal flash memory.
*/
void addToConfig(JsonObject& root) {
JsonObject staircase = root[FPSTR(_name)];
if (staircase.isNull()) {
staircase = root.createNestedObject(FPSTR(_name));
}
staircase[FPSTR(_enabled)] = enabled;
staircase[FPSTR(_sonarTriggerPin)] = triggerPin;
staircase[FPSTR(_sonarEchoPin)] = echoPin;
staircase[FPSTR(_topPIRPin)] = topPIRPin;
staircase[FPSTR(_bottomPIRPin)] = bottomPIRPin;
staircase[FPSTR(_HAautodiscovery)] = HAautodiscovery;
DEBUG_PRINTLN(F("Staircase config saved."));
}
/*
* Reads the configuration to internal flash memory before setup() is called.
*
* The function should return true if configuration was successfully loaded or false if there was no configuration.
*/
bool readFromConfig(JsonObject& root) {
int8_t oldTriggerPin = triggerPin;
int8_t oldEchoPin = echoPin;
int8_t oldTopPirPin = topPIRPin;
int8_t oldBottomPirPin = bottomPIRPin;
JsonObject top = root[FPSTR(_name)];
if (top.isNull()) {
DEBUG_PRINT(FPSTR(_name));
DEBUG_PRINTLN(F(": No config found. (Using defaults.)"));
return false;
}
enabled = top[FPSTR(_enabled)] | enabled;
HAautodiscovery = top[FPSTR(_HAautodiscovery)] | HAautodiscovery;
endOfStairsDistance = top[FPSTR(_endOfStairsDistance)] | endOfStairsDistance;
triggerPin = top[FPSTR(_sonarTriggerPin)] | triggerPin;
echoPin = top[FPSTR(_sonarEchoPin)] | echoPin;
topPIRPin = top[FPSTR(_topPIRPin)] | topPIRPin;
bottomPIRPin = top[FPSTR(_bottomPIRPin)] | bottomPIRPin;
DEBUG_PRINT(FPSTR(_name));
if (!initDone) {
// first run: reading from cfg.json
DEBUG_PRINTLN(F(" config loaded."));
} else {
// changing parameters from settings page
DEBUG_PRINTLN(F(" config (re)loaded."));
bool changed = false;
if ((oldTriggerPin != triggerPin) ||
(oldTopPirPin != topPIRPin) ||
(oldBottomPirPin != bottomPIRPin) ||
(oldEchoPin != echoPin)) {
changed = true;
pinManager.deallocatePin(oldTriggerPin, PinOwner::UM_DistanceStaircase);
pinManager.deallocatePin(oldEchoPin, PinOwner::UM_DistanceStaircase);
pinManager.deallocatePin(oldTopPirPin, PinOwner::UM_DistanceStaircase);
pinManager.deallocatePin(oldBottomPirPin, PinOwner::UM_DistanceStaircase);
}
if (changed) setup();
}
return true;
}
void addToJsonInfo(JsonObject& root) {
JsonObject user = root["u"];
if (user.isNull()) {
user = root.createNestedObject("u");
}
JsonArray infoArr = user.createNestedArray(FPSTR(_name)); // name
String uiDomString = F(" <button class=\"btn btn-xs\" onclick=\"requestJson({");
uiDomString += FPSTR(_name);
uiDomString += F(":{");
uiDomString += FPSTR(_enabled);
if (enabled) {
uiDomString += F(":false}});\">");
uiDomString += F("<i class=\"icons on\">&#xe325;</i>");
} else {
uiDomString += F(":true}});\">");
uiDomString += F("<i class=\"icons off\">&#xe08f;</i>");
}
uiDomString += F("</button>");
infoArr.add(uiDomString);
infoArr.add(distanceState.value);
}
};
// strings to reduce flash memory usage (used more than twice)
const char Distance_Staircase::_name[] PROGMEM = "staircase";
const char Distance_Staircase::_onTime[] PROGMEM = "maxTimeSeconds";
const char Distance_Staircase::_enabled[] PROGMEM = "enabled";
const char Distance_Staircase::_endOfStairsDistance[] PROGMEM = "endOfStairsDistanceCM";
const char Distance_Staircase::_sonarTriggerPin[] PROGMEM = "SonarTriggerPin";
const char Distance_Staircase::_sonarEchoPin[] PROGMEM = "SonarEchoPin";
const char Distance_Staircase::_topPIRPin[] PROGMEM = "TopPIRPin";
const char Distance_Staircase::_bottomPIRPin[] PROGMEM = "BottomPIRPin";
const char Distance_Staircase::_HAautodiscovery[] PROGMEM = "HA-autodiscovery";

Wyświetl plik

@ -0,0 +1,78 @@
# Usermod Distance Staircase
This usermod is a modification of the animated staircase usermod and makes your staircase look cool by illuminating it with an animation. It uses PIR and ultrasonic sensors. At the Top and bottom are PIR sensors to detect entering the staircase.
The ultrasonic sensor detects how far one is through the staircase.
- Light up the steps in the direction you're walking. At the position you are.
- Switch off the steps after you, in the direction of the last detected movement.
## WLED integration
To include this usermod in your WLED setup, you have to be able to [compile WLED from source](https://kno.wled.ge/advanced/compiling-wled/).
Before compiling, you have to make the following modifications:
Edit `usermods_list.cpp`:
1. Open `wled00/usermods_list.cpp`
2. add `#include "../usermods/Animated_Staircase/Animated_Staircase.h"` to the top of the file
3. add `usermods.add(new Animated_Staircase());` to the end of the `void registerUsermods()` function.
Or just add `-D USERMOD_DISTANCE_STAIRCASE` to the build arguments.
You can configure usermod using the Usermods settings page.
Please enter GPIO pins for PIR and ultrasonic sensors (trigger and echo).
## Hardware installation
1. Attach the LED strip to each step of the stairs.
3. Connect the data-out pin at the end of each strip per step to the data-in pin on the
next step, creating one large virtual LED strip.
4. Mount PIR sensors at the bottom and top of the stairs and connect them to the ESP.
5. Mount the US sensor in line with the stairs. E.g. at the top looking down.
5. To make sure all LEDs get enough power and have your staircase lighted evenly, power each
step from one side, using at least AWG14 or 2.5mm^2 cable. Don't connect them serial as you
do for the datacable!
You _may_ need to use 10k pull-down resistors on the selected PIR pins, depending on the sensor.
## WLED configuration
1. In the WLED UI, configure a segment for each step. The highest step of the stairs is the
lowest segment id.
2. Save your segments into a preset.
3. Ideally, add the preset in the config > LED setup menu to the "apply
preset **n** at boot" setting.
To read the current settings, open a browser to `http://xxx.xxx.xxx.xxx/json/state` (use your WLED
device IP address). The device will respond with a json object containing all WLED settings.
The staircase settings and sensor states are inside the WLED "state" element:
```json
{
"state": {
"staircase": {
"enabled": true,
"bottom-sensor": false,
"top-sensor": false
},
}
```
### Enable/disable the usermod
By disabling the usermod you will be able to keep the LED's on, independent from the sensor
activity. This enables you to play with the lights without the usermod switching them on or off.
To disable the usermod:
```bash
curl -X POST -H "Content-Type: application/json" \
-d {"staircase":{"enabled":false}} \
xxx.xxx.xxx.xxx/json/state
```
To enable the usermod again, use `"enabled":true`.
Alternatively you can use _Usermod_ Settings page where you can change other parameters as well.
**Please note:** using an HC-SR04 sensor, particularly when detecting echos at longer
distances creates delays in the WLED software, _might_ introduce timing hiccups in your animation or
a less responsive web interface. It is therefore advised to keep the detection distance as short as possible.
**MQTT**
All sensors can be auto detected by Homeassistant and publish their values.

Wyświetl plik

@ -152,6 +152,7 @@
#define USERMOD_ID_INTERNAL_TEMPERATURE 42 //Usermod "usermod_internal_temperature.h"
#define USERMOD_ID_LDR_DUSK_DAWN 43 //Usermod "usermod_LDR_Dusk_Dawn_v2.h"
#define USERMOD_ID_STAIRWAY_WIPE 44 //Usermod "stairway-wipe-usermod-v2.h"
#define USERMOD_ID_DISTANCE_STAIRCASE 45 //Usermod "Distance_Staircase.h"
//Access point behavior
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot

Wyświetl plik

@ -61,7 +61,8 @@ enum struct PinOwner : uint8_t {
UM_Audioreactive = USERMOD_ID_AUDIOREACTIVE, // 0x20 // Usermod "audio_reactive.h"
UM_SdCard = USERMOD_ID_SD_CARD, // 0x25 // Usermod "usermod_sd_card.h"
UM_PWM_OUTPUTS = USERMOD_ID_PWM_OUTPUTS, // 0x26 // Usermod "usermod_pwm_outputs.h"
UM_LDR_DUSK_DAWN = USERMOD_ID_LDR_DUSK_DAWN // 0x2B // Usermod "usermod_LDR_Dusk_Dawn_v2.h"
UM_LDR_DUSK_DAWN = USERMOD_ID_LDR_DUSK_DAWN, // 0x2B // Usermod "usermod_LDR_Dusk_Dawn_v2.h"
UM_DistanceStaircase = USERMOD_ID_DISTANCE_STAIRCASE // 0x2C // Usermod "Distance_Staircase.h"
};
static_assert(0u == static_cast<uint8_t>(PinOwner::None), "PinOwner::None must be zero, so default array initialization works as expected");

Wyświetl plik

@ -89,6 +89,10 @@
#include "../usermods/Animated_Staircase/Animated_Staircase.h"
#endif
#ifdef USERMOD_DISTANCE_STAIRCASE
#include "../usermods/Distance_Staircase/Distance_Staircase.h"
#endif
#ifdef USERMOD_MULTI_RELAY
#include "../usermods/multi_relay/usermod_multi_relay.h"
#endif
@ -276,6 +280,10 @@ void registerUsermods()
usermods.add(new Animated_Staircase());
#endif
#ifdef USERMOD_DISTANCE_STAIRCASE
usermods.add(new Distance_Staircase());
#endif
#ifdef USERMOD_MULTI_RELAY
usermods.add(new MultiRelay());
#endif