Skip to content

Commit 1835937

Browse files
authored
Merge pull request #4 from davirxavier/feature/scheduling
Feature/scheduling
2 parents a24aabc + 4d942f5 commit 1835937

File tree

8 files changed

+1513
-95
lines changed

8 files changed

+1513
-95
lines changed

EmberChannelDefinition.h

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@
3434
#ifndef EMBERCHANNELDEF_H
3535
#define EMBERCHANNELDEF_H
3636

37+
#define EMBER_BUTTON_OFF 0
38+
#define EMBER_BUTTON_ON 1
39+
#define EMBER_BUTTON_PUSH 2
40+
3741
class EmberIotProp
3842
{
3943
public:
@@ -66,6 +70,15 @@ class EmberIotProp
6670
return this->data;
6771
}
6872

73+
bool toButtonIsOn() const
74+
{
75+
return toInt() == EMBER_BUTTON_ON;
76+
}
77+
78+
bool toButtonIsPush() const {
79+
return toInt() == EMBER_BUTTON_PUSH;
80+
}
81+
6982
/**
7083
* True if the value itself has changed from the last emitted value.
7184
*/
@@ -987,7 +1000,9 @@ EmberIotUpdateCallback callbacks[EMBER_CHANNEL_COUNT] = {
9871000
#endif
9881001
};
9891002

990-
#define EMBER_CHANNEL_CB(channel) \
991-
void ember_channel_cb_##channel (const EmberIotProp &prop)
1003+
// Macro indirection for forcing expansion, so users are able to use macros as a parameter to EMBER_CHANNEL_CB
1004+
#define EMBER_CH_CB_IN(x) void ember_channel_cb_##x (const EmberIotProp &prop)
1005+
#define EMBER_CH_CB_IN_INDIR(x) EMBER_CH_CB_IN(x)
1006+
#define EMBER_CHANNEL_CB(x) EMBER_CH_CB_IN_INDIR(x)
9921007

9931008
#endif

EmberIot.h

Lines changed: 93 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,10 @@
3838
#include <EmberIotUtil.h>
3939
#include <WithSecureClient.h>
4040
#include <EmberIotAuth.h>
41-
#include <EmberIotShared.h>
4241
#include <EmberIotStream.h>
4342
#include <time.h>
4443

4544
#define UPDATE_LAST_SEEN_INTERVAL 120000
46-
#define EMBER_BUTTON_OFF 0
47-
#define EMBER_BUTTON_ON 1
48-
#define EMBER_BUTTON_PUSH 2
4945

5046
/**
5147
* @param dbUrl Realtime database URL, without protocol and slashes at the end. Example value: my-rtdb.firebaseio.com
@@ -172,6 +168,8 @@ class EmberIot : WithSecureClient
172168
return;
173169
}
174170

171+
runPendingSchedules();
172+
175173
uint8_t updateCount = 0;
176174
for (const bool i : hasUpdateByChannel)
177175
{
@@ -192,6 +190,14 @@ class EmberIot : WithSecureClient
192190
#endif
193191
if (result)
194192
{
193+
for (size_t i = 0; i < EMBER_CHANNEL_COUNT; i++)
194+
{
195+
if (hasUpdateByChannel[i])
196+
{
197+
snprintf(EmberIotChannels::lastValues[i], EMBER_MAXIMUM_STRING_SIZE, "%s", updateDataByChannel[i]);
198+
}
199+
}
200+
195201
for (bool& i : hasUpdateByChannel)
196202
{
197203
i = false;
@@ -206,14 +212,29 @@ class EmberIot : WithSecureClient
206212
lastUpdatedChannels = millis();
207213
}
208214

215+
EmberIotProp getChannelLastValue(const int channel)
216+
{
217+
return EmberIotProp(EmberIotChannels::lastValues[channel], false);
218+
}
219+
220+
/**
221+
* Sets a callback to be executed when a scheduled action runs.
222+
* @param scheduleId schedule id.
223+
* @param callback function to be executed.
224+
*/
225+
void setScheduleCallback(int scheduleId, EmberIotChannels::ScheduleJobCallback callback)
226+
{
227+
EmberIotChannels::setScheduleCallback(scheduleId, callback);
228+
}
229+
209230
/**
210231
* Writes a string to a data channel.
211232
* @param channel Channel number.
212233
* @param value Value to be written.
213234
*/
214235
void channelWrite(uint8_t channel, const char* value)
215236
{
216-
if (!checkChannelChanged(updateDataByChannel[channel], value))
237+
if (hasUpdateByChannel[channel] && !checkChannelChanged(updateDataByChannel[channel], value))
217238
{
218239
return;
219240
}
@@ -291,6 +312,73 @@ class EmberIot : WithSecureClient
291312
}
292313

293314
private:
315+
void runPendingSchedules()
316+
{
317+
time_t now = time(nullptr);
318+
319+
for (size_t i = 0; i < EMBER_MAX_SCHEDULES; i++)
320+
{
321+
EmberIotChannels::ScheduleJob *job = EmberIotChannels::jobs[i];
322+
if (job == nullptr || job->nextExecution < 0 || job->nextExecution > now || job->dataChannel < 0 || job->dataChannel >= EMBER_CHANNEL_COUNT)
323+
{
324+
continue;
325+
}
326+
327+
char writtenData[EMBER_MAXIMUM_STRING_SIZE]{};
328+
switch (tolower(job->mode))
329+
{
330+
case EmberIotChannels::JOB_MODE_DECREMENT:
331+
case EmberIotChannels::JOB_MODE_INCREMENT:
332+
{
333+
double out;
334+
FirePropUtil::str2int_errno ret = FirePropUtil::str2double(&out, job->value);
335+
if (ret != FirePropUtil::STR2INT_SUCCESS)
336+
{
337+
EMBER_DEBUGF("Error parsing job value/str: %d/%s\n", ret, job->value);
338+
break;
339+
}
340+
341+
double dataChannelValue;
342+
FirePropUtil::str2int_errno retChannel = FirePropUtil::str2double(&dataChannelValue, EmberIotChannels::lastValues[job->dataChannel]);
343+
if (retChannel == FirePropUtil::STR2INT_INCONVERTIBLE)
344+
{
345+
EMBER_DEBUGN("Current data in channel is inconvertible to a number, setting to schedule value.");
346+
channelWrite(job->dataChannel, job->value);
347+
snprintf(writtenData, sizeof(writtenData), "%s", job->value);
348+
break;
349+
}
350+
else if (retChannel != FirePropUtil::STR2INT_SUCCESS)
351+
{
352+
EMBER_DEBUGF("Error parsing data channel value/str: %d/%s\n", ret, EmberIotChannels::lastValues[job->dataChannel]);
353+
break;
354+
}
355+
356+
double newValue = job->mode == EmberIotChannels::JOB_MODE_INCREMENT ? dataChannelValue + out : dataChannelValue - out;
357+
channelWrite(job->dataChannel, newValue);
358+
snprintf(writtenData, sizeof(writtenData), "%lf", newValue);
359+
break;
360+
}
361+
default:
362+
{
363+
channelWrite(job->dataChannel, job->value);
364+
snprintf(writtenData, sizeof(writtenData), "%s", job->value);
365+
}
366+
}
367+
368+
EmberIotChannels::updateScheduleNextExecution(job->scheduleId);
369+
370+
if (EmberIotChannels::jobCallbacks[job->scheduleId] != nullptr)
371+
{
372+
EmberIotChannels::jobCallbacks[job->scheduleId](job);
373+
}
374+
375+
if (strlen(writtenData) > 0)
376+
{
377+
EmberIotChannels::callChannelUpdate(job->dataChannel, writtenData, "sched");
378+
}
379+
}
380+
}
381+
294382
bool checkChannelChanged(const char *lastVal, const char *newVal)
295383
{
296384
if (lastVal != nullptr && newVal == nullptr)

EmberIotNotifications.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,8 @@ class FCMEmberNotifications
197197
return;
198198
}
199199

200-
if (!FirePropUtil::isTimeInitialized() || clientPtr == nullptr)
200+
201+
if (WiFi.status() != WL_CONNECTED || !FirePropUtil::isTimeInitialized() || clientPtr == nullptr)
201202
{
202203
return;
203204
}
@@ -393,6 +394,7 @@ class FCMEmberNotifications
393394
#endif
394395

395396
HTTP_LOGN("Send pending notifications.");
397+
unsigned long timeCounter = 0;
396398

397399
EmberIotNotification notif = notificationQueue[currentNotification-1];
398400

@@ -503,7 +505,7 @@ class FCMEmberNotifications
503505

504506
if (HTTP_UTIL::isSuccess(responseStatus))
505507
{
506-
HTTP_LOGN("Notification sent successfully.");
508+
HTTP_LOGF("Notification sent successfully, time taken: %lu\n", millis() - timeCounter);
507509
currentNotification--;
508510
}
509511
else

0 commit comments

Comments
 (0)