-
Notifications
You must be signed in to change notification settings - Fork 293
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WIP] Add MQTT notifications #102
Conversation
09cdad3
to
1cd8638
Compare
@jbaudoux , this looks great. I did something similar to add InfluxDb/Grafana support to OpenSprinkler to enable dashboard logging here. A few things worth thinking about:
Anyway if you want some help on this then happy to work with you. I would be interested in thinking through the message protocol and I have both OSPi and OS dev environments. It would be great to decommission my custom code and use out-of-the-box functionality. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Had a quick pass through the code and added a few comments/questions below. It is quite late here so sorry if I misinterpreted anything.
mqtt_client = mosquitto_new(NULL, clean_session, NULL); | ||
if (!mqtt_client) { | ||
DEBUG_PRINTLN("CANNOT CREATE MQTT CLIENT"); | ||
return 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you need to continue rather than return so that start_network()
can properly configure m_server
with the right port settings..
} | ||
if (mosquitto_connect(mqtt_client, DEFAULT_MQTT_HOST, DEFAULT_MQTT_PORT, keepalive)) { | ||
DEBUG_PRINTLN("CANNOT CONNECT TO MQTT"); | ||
return 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As above
@@ -15,7 +15,7 @@ if [ "$1" == "demo" ]; then | |||
elif [ "$1" == "osbo" ]; then | |||
g++ -o OpenSprinkler -DOSBO main.cpp OpenSprinkler.cpp program.cpp server.cpp utils.cpp weather.cpp gpio.cpp etherport.cpp -lpthread | |||
else | |||
g++ -o OpenSprinkler -DOSPI main.cpp OpenSprinkler.cpp program.cpp server.cpp utils.cpp weather.cpp gpio.cpp etherport.cpp -lpthread | |||
g++ -o OpenSprinkler -DOSPI -DMQTT main.cpp OpenSprinkler.cpp program.cpp server.cpp utils.cpp weather.cpp gpio.cpp etherport.cpp -lpthread -lmosquitto |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggest once you get past WIP that this becomes a default feature through -DOSPI rather than having a feature specific #define.
itoa(ip[i], str+strlen(str), 10); | ||
if(i!=3) strcat(str, "."); | ||
} | ||
sprintf_P(str+strlen(str), PSTR("%d.%d.%d.%d"), ip[0], ip[1], ip[2], ip[3]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Worth checking with Ray the backward compatibility requirement. I know in the early days that OS memory was limited and sprintf
was left out. That may no longer be the case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree. I did initially this change because my compiler was complaining about itoa and remembered that sprintf is better approach in C. Then I though it was maybe a bad idea for arduino/esp OS. Impact must definitely be tested.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sprintf is fine now: from firmware 2.1.9 we no longer supports legacy OS (any version prior to OS 2.3). Any current OS hardware has plenty of RAM and program space, so we are no longer limited by memory.
} | ||
|
||
void push_message(byte type, uint32_t lval, float fval, const char* sval) { | ||
// check if this type of event is enabled for push notification | ||
byte test_type = (type != NOTIFY_STATION_ON) ? type : NOTIFY_STATION_OFF; | ||
if(!os.options[OPTION_IFTTT_ENABLE]&test_type && !os.options[OPTION_MQTT_ENABLE]&test_type) return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You replicate the bitwise & many times. Might be worth creating two bools for send_mqtt
and send_ifft
as it would read easier.
@@ -489,6 +499,23 @@ extern char ether_buffer[]; | |||
|
|||
/** Initialize network with the given mac address and http port */ | |||
byte OpenSprinkler::start_network() { | |||
#ifdef MQTT | |||
if (options[OPTION_MQTT_ENABLE]) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think for MQTT it makes more sense for this to be a binary enable/disable flag rather than a bitwise mask. For MQTT , the client determines which messages to subscribe to rather than the server. It is a bit different for IFTTT which is primarily used to generate text messages to the user and therefore OS is where the user does the selection.
|
||
void OpenSprinkler::mqtt_publish(const char *topic, const char *payload) { | ||
#if defined(MQTT) && defined(OSPI) | ||
int rc = mosquitto_reconnect(mqtt_client); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should check for mqtt_client != NULL
as it may have failed during network_start()
.
#define NOTIFY_WEATHER_UPDATE 0x08 | ||
#define NOTIFY_REBOOT 0x10 | ||
#define NOTIFY_STATION_OFF 0x20 | ||
#define NOTIFY_STATION_ON 0x40 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the list still WIP ? It looks a bit inconsistent with the App PR ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with your suggestion that we can keep this list only for IFTTT and only have a global enable flag on MQTT
@@ -207,6 +208,8 @@ typedef unsigned long ulong; | |||
#define DEFAULT_JAVASCRIPT_URL "https://ui.opensprinkler.com/js" | |||
#define DEFAULT_WEATHER_URL "weather.opensprinkler.com" | |||
#define DEFAULT_IFTTT_URL "maker.ifttt.com" | |||
#define DEFAULT_MQTT_HOST "localhost" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would suggest HOST and PORT need to be configurable from App as part of minimum viable product.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
sprintf_P(payload, PSTR("{\"count\":%d,\"volume\":%.2f}"), lval, (float)volume/100); | ||
} | ||
if (os.options[OPTION_IFTTT_ENABLE]&test_type) { | ||
sprintf_P(postval+strlen(postval), PSTR("Flow count: %d, volume: %.2f"), lval, (float)volume/100); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure that arduino sprintf
supports floats ? I remember that you had jump through hoops when it came to formatting floats and use dtostrf()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@PeteBa Thanks for the involvement. In fact, I did this to integrate with InfluxDb/Grafana. If you have a more advanced PR doing all this, we can replace mine with yours. Otherwise, can you make a PR on mine that improves it with those features?
|
@jbaudoux my approach has been using direct REST calls to InfluxDb in their write protocol. Unfortunately, that is pretty niche and unlikely to get out-of-the-box support in OS. Whereas MQTT is a far more widespread protocol and is something I know Ray is interested in. Hence, I think you are on the right track with this PR. To be of some help, I have written up the code for Firmware and App to allow configuring the broker's server and port details. The commits are on my fork and you can take a look at the following links ( Firmware and App ). It is pretty rough-and-ready but works and follows the same design approach as used elsewhere in the code for IFTTT and Weather Options. Feel free to incorporate into this PR. In terms of multi-OS support, it might make sense to just put a placeholder, e.g. |
Replaced by #108 |
Send MQTT messages. Same events as IFTTT can be subscribed. IFTTT and/or MQTT can be enabled.
Tested MQTT on OSPI using libmosquitto. For arduino-like, code must be extended to use pubsubclient library.
I also rewrite some IFTTT string message generation to use the standard sprintf instead of non-standard itoa. While cleaner for OSPI, I don't know if it was a good idea for arduino-like as it will maybe increase sketch size.
App PR is here: OpenSprinkler/OpenSprinkler-App#80