Skip to content

Commit f535dcd

Browse files
committed
Add $retained attribute to properties (Homie 3.0.1) and button example
1 parent 11c6bb2 commit f535dcd

File tree

6 files changed

+94
-13
lines changed

6 files changed

+94
-13
lines changed
+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#include <Homie.h>
2+
3+
const int PIN_BUTTON = 5; // D1
4+
5+
int buttonState = 0;
6+
bool buttonPressed = false;
7+
8+
HomieNode buttonNode("button", "Button", "button");
9+
10+
void loopHandler() {
11+
buttonState = !digitalRead(PIN_BUTTON);
12+
13+
if (buttonState == HIGH && !buttonPressed) {
14+
buttonNode.setProperty("button").send("PRESSED");
15+
Homie.getLogger() << "Button pressed" << endl;
16+
buttonPressed = true;
17+
} else if (buttonState == LOW && buttonPressed) {
18+
buttonNode.setProperty("button").send("RELEASED");
19+
Homie.getLogger() << "Button released" << endl;
20+
buttonPressed = false;
21+
}
22+
}
23+
24+
void setup() {
25+
Serial.begin(115200);
26+
Serial << endl << endl;
27+
Homie_setFirmware("awesome-button", "1.0.0");
28+
Homie.setLoopFunction(loopHandler);
29+
30+
pinMode(PIN_BUTTON, INPUT_PULLUP);
31+
32+
buttonNode.advertise("button").setName("Button")
33+
.setDatatype("enum")
34+
.setFormat("PRESSED,RELEASED")
35+
.retained(false);
36+
37+
Homie.setup();
38+
}
39+
40+
void loop() {
41+
Homie.loop();
42+
}

src/Homie/Boot/BootNormal.cpp

+22-9
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ void BootNormal::setup() {
4545
if (nodeMaxTopicLength > longestSubtopicLength) longestSubtopicLength = nodeMaxTopicLength;
4646

4747
for (Property* iProperty : iNode->getProperties()) {
48-
size_t propertyMaxTopicLength = 1 + strlen(iNode->getId()) + 1 + strlen(iProperty->getProperty()) + 1;
48+
size_t propertyMaxTopicLength = 1 + strlen(iNode->getId()) + 1 + strlen(iProperty->getId()) + 1;
4949
if (iProperty->isSettable()) propertyMaxTopicLength += 4; // /set
5050

5151
if (propertyMaxTopicLength > longestSubtopicLength) longestSubtopicLength = propertyMaxTopicLength;
@@ -477,7 +477,7 @@ void BootNormal::_advertise() {
477477
strcat_P(subtopic.get(), PSTR("/$properties"));
478478
String properties;
479479
for (Property* iProperty : node->getProperties()) {
480-
properties.concat(iProperty->getProperty());
480+
properties.concat(iProperty->getId());
481481
properties.concat(",");
482482
}
483483
if (node->getProperties().size() >= 1) properties.remove(properties.length() - 1);
@@ -508,14 +508,14 @@ void BootNormal::_advertise() {
508508
{
509509
HomieNode* node = HomieNode::nodes[_advertisementProgress.currentNodeIndex];
510510
Property* iProperty = node->getProperties()[_advertisementProgress.currentPropertyIndex];
511-
std::unique_ptr<char[]> subtopic = std::unique_ptr<char[]>(new char[1 + strlen(node->getId()) + 1 +strlen(iProperty->getProperty()) + 10 + 1]); // /nodeId/propId/$settable
511+
std::unique_ptr<char[]> subtopic = std::unique_ptr<char[]>(new char[1 + strlen(node->getId()) + 1 +strlen(iProperty->getId()) + 10 + 1]); // /nodeId/propId/$settable
512512
switch (_advertisementProgress.propertyStep) {
513513
case AdvertisementProgress::PropertyStep::PUB_NAME:
514514
if (iProperty->getName() && (iProperty->getName()[0] != '\0')) {
515515
strcpy_P(subtopic.get(), PSTR("/"));
516516
strcat(subtopic.get(), node->getId());
517517
strcat_P(subtopic.get(), PSTR("/"));
518-
strcat(subtopic.get(), iProperty->getProperty());
518+
strcat(subtopic.get(), iProperty->getId());
519519
strcat_P(subtopic.get(), PSTR("/$name"));
520520
packetId = Interface::get().getMqttClient().publish(_prefixMqttTopic(subtopic.get()), 1, true, iProperty->getName());
521521
if (packetId != 0) _advertisementProgress.propertyStep = AdvertisementProgress::PropertyStep::PUB_SETTABLE;
@@ -528,9 +528,22 @@ void BootNormal::_advertise() {
528528
strcpy_P(subtopic.get(), PSTR("/"));
529529
strcat(subtopic.get(), node->getId());
530530
strcat_P(subtopic.get(), PSTR("/"));
531-
strcat(subtopic.get(), iProperty->getProperty());
531+
strcat(subtopic.get(), iProperty->getId());
532532
strcat_P(subtopic.get(), PSTR("/$settable"));
533533
packetId = Interface::get().getMqttClient().publish(_prefixMqttTopic(subtopic.get()), 1, true, "true");
534+
if (packetId != 0) _advertisementProgress.propertyStep = AdvertisementProgress::PropertyStep::PUB_RETAINED;
535+
} else {
536+
_advertisementProgress.propertyStep = AdvertisementProgress::PropertyStep::PUB_RETAINED;
537+
}
538+
break;
539+
case AdvertisementProgress::PropertyStep::PUB_RETAINED:
540+
if (!iProperty->isRetained()) {
541+
strcpy_P(subtopic.get(), PSTR("/"));
542+
strcat(subtopic.get(), node->getId());
543+
strcat_P(subtopic.get(), PSTR("/"));
544+
strcat(subtopic.get(), iProperty->getId());
545+
strcat_P(subtopic.get(), PSTR("/$retained"));
546+
packetId = Interface::get().getMqttClient().publish(_prefixMqttTopic(subtopic.get()), 1, true, "false");
534547
if (packetId != 0) _advertisementProgress.propertyStep = AdvertisementProgress::PropertyStep::PUB_DATATYPE;
535548
} else {
536549
_advertisementProgress.propertyStep = AdvertisementProgress::PropertyStep::PUB_DATATYPE;
@@ -541,7 +554,7 @@ void BootNormal::_advertise() {
541554
strcpy_P(subtopic.get(), PSTR("/"));
542555
strcat(subtopic.get(), node->getId());
543556
strcat_P(subtopic.get(), PSTR("/"));
544-
strcat(subtopic.get(), iProperty->getProperty());
557+
strcat(subtopic.get(), iProperty->getId());
545558
strcat_P(subtopic.get(), PSTR("/$datatype"));
546559
packetId = Interface::get().getMqttClient().publish(_prefixMqttTopic(subtopic.get()), 1, true, iProperty->getDatatype());
547560
if (packetId != 0) _advertisementProgress.propertyStep = AdvertisementProgress::PropertyStep::PUB_UNIT;
@@ -554,7 +567,7 @@ void BootNormal::_advertise() {
554567
strcpy_P(subtopic.get(), PSTR("/"));
555568
strcat(subtopic.get(), node->getId());
556569
strcat_P(subtopic.get(), PSTR("/"));
557-
strcat(subtopic.get(), iProperty->getProperty());
570+
strcat(subtopic.get(), iProperty->getId());
558571
strcat_P(subtopic.get(), PSTR("/$unit"));
559572
packetId = Interface::get().getMqttClient().publish(_prefixMqttTopic(subtopic.get()), 1, true, iProperty->getUnit());
560573
if (packetId != 0) _advertisementProgress.propertyStep = AdvertisementProgress::PropertyStep::PUB_FORMAT;
@@ -569,7 +582,7 @@ void BootNormal::_advertise() {
569582
strcpy_P(subtopic.get(), PSTR("/"));
570583
strcat(subtopic.get(), node->getId());
571584
strcat_P(subtopic.get(), PSTR("/"));
572-
strcat(subtopic.get(), iProperty->getProperty());
585+
strcat(subtopic.get(), iProperty->getId());
573586
strcat_P(subtopic.get(), PSTR("/$format"));
574587
packetId = Interface::get().getMqttClient().publish(_prefixMqttTopic(subtopic.get()), 1, true, iProperty->getFormat());
575588
if (packetId != 0) sent = true;
@@ -1053,7 +1066,7 @@ bool HomieInternals::BootNormal::__handleNodeProperty(char * topic, char * paylo
10531066

10541067
Property* propertyObject = nullptr;
10551068
for (Property* iProperty : homieNode->getProperties()) {
1056-
if (strcmp(property, iProperty->getProperty()) == 0) {
1069+
if (strcmp(property, iProperty->getId()) == 0) {
10571070
propertyObject = iProperty;
10581071
break;
10591072
}

src/Homie/Boot/BootNormal.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ class BootNormal : public Boot {
6868
enum class PropertyStep {
6969
PUB_NAME,
7070
PUB_SETTABLE,
71+
PUB_RETAINED,
7172
PUB_DATATYPE,
7273
PUB_UNIT,
7374
PUB_FORMAT

src/Homie/Constants.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#include <ESP8266WiFi.h>
44

55
namespace HomieInternals {
6-
const char HOMIE_VERSION[] = "3.0.0";
6+
const char HOMIE_VERSION[] = "3.0.1";
77
const char HOMIE_ESP8266_VERSION[] = "3.0.0";
88

99
const IPAddress ACCESS_POINT_IP(192, 168, 123, 1);

src/HomieNode.cpp

+20-1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ PropertyInterface& PropertyInterface::setFormat(const char* format) {
3434
return *this;
3535
}
3636

37+
PropertyInterface& PropertyInterface::retained(const bool retained) {
38+
_property->retained(retained);
39+
return *this;
40+
}
41+
3742
PropertyInterface& PropertyInterface::setProperty(Property* property) {
3843
_property = property;
3944
return *this;
@@ -71,7 +76,21 @@ PropertyInterface& HomieNode::advertise(const char* id) {
7176
}
7277

7378
SendingPromise& HomieNode::setProperty(const String& property) const {
74-
return Interface::get().getSendingPromise().setNode(*this).setProperty(property).setQos(1).setRetained(true).overwriteSetter(false).setRange({ .isRange = false, .index = 0 });
79+
Property* iProperty = this->getProperty(property);
80+
if (iProperty) {
81+
if (iProperty->isRetained())
82+
return Interface::get().getSendingPromise().setNode(*this).setProperty(property).setQos(1).setRetained(true);
83+
else
84+
return Interface::get().getSendingPromise().setNode(*this).setProperty(property).setQos(1);
85+
}
86+
}
87+
88+
Property* HomieNode::getProperty(const String& property) const {
89+
for (Property* iProperty : getProperties()) {
90+
if (strcmp(iProperty->getId(), property.c_str()) == 0)
91+
return iProperty;
92+
}
93+
return NULL;
7594
}
7695

7796
bool HomieNode::handleInput(const HomieRange& range, const String& property, const String& value) {

src/HomieNode.hpp

+8-2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class PropertyInterface {
2929
PropertyInterface& setUnit(const char* unit);
3030
PropertyInterface& setDatatype(const char* datatype);
3131
PropertyInterface& setFormat(const char* format);
32+
PropertyInterface& retained(const bool retained = true);
3233

3334
private:
3435
PropertyInterface& setProperty(Property* property);
@@ -37,31 +38,35 @@ class PropertyInterface {
3738
};
3839

3940
class Property {
41+
friend HomieNode;
4042
friend BootNormal;
4143

4244
public:
4345
explicit Property(const char* id) {
44-
_id = strdup(id); _name = ""; _unit = ""; _datatype = ""; _format = ""; _settable = false; }
46+
_id = strdup(id); _name = ""; _unit = ""; _datatype = ""; _format = ""; _retained = true; _settable = false; }
4547
void settable(const PropertyInputHandler& inputHandler) { _settable = true; _inputHandler = inputHandler; }
4648
void setName(const char* name) { _name = name; }
4749
void setUnit(const char* unit) { _unit = unit; }
4850
void setDatatype(const char* datatype) { _datatype = datatype; }
4951
void setFormat(const char* format) { _format = format; }
52+
void retained(const bool retained = true) { _retained = retained; }
5053

5154

5255
private:
53-
const char* getProperty() const { return _id; }
56+
const char* getId() const { return _id; }
5457
const char* getName() const { return _name; }
5558
const char* getUnit() const { return _unit; }
5659
const char* getDatatype() const { return _datatype; }
5760
const char* getFormat() const { return _format; }
61+
bool isRetained() const { return _retained; }
5862
bool isSettable() const { return _settable; }
5963
PropertyInputHandler getInputHandler() const { return _inputHandler; }
6064
const char* _id;
6165
const char* _name;
6266
const char* _unit;
6367
const char* _datatype;
6468
const char* _format;
69+
bool _retained;
6570
bool _settable;
6671
PropertyInputHandler _inputHandler;
6772
};
@@ -85,6 +90,7 @@ class HomieNode {
8590

8691
HomieInternals::PropertyInterface& advertise(const char* id);
8792
HomieInternals::SendingPromise& setProperty(const String& property) const;
93+
HomieInternals::Property* getProperty(const String& property) const;
8894

8995
protected:
9096
virtual void setup() {}

0 commit comments

Comments
 (0)