From 30cfea3db02c47630b96e5a7069335b98a524036 Mon Sep 17 00:00:00 2001 From: pennam Date: Tue, 5 Oct 2021 11:52:19 +0200 Subject: [PATCH 01/27] Initial scheduler implementation --- src/property/PropertyContainer.h | 1 + src/property/types/CloudScheduler.h | 190 ++++++++++++++++++++++++++++ 2 files changed, 191 insertions(+) create mode 100644 src/property/types/CloudScheduler.h diff --git a/src/property/PropertyContainer.h b/src/property/PropertyContainer.h index fc038f583..65882afe4 100644 --- a/src/property/PropertyContainer.h +++ b/src/property/PropertyContainer.h @@ -40,6 +40,7 @@ #include "types/CloudUnsignedInt.h" #include "types/CloudString.h" #include "types/CloudLocation.h" +#include "types/CloudScheduler.h" #include "types/CloudColor.h" #include "types/CloudWrapperBase.h" diff --git a/src/property/types/CloudScheduler.h b/src/property/types/CloudScheduler.h new file mode 100644 index 000000000..97d6f45fe --- /dev/null +++ b/src/property/types/CloudScheduler.h @@ -0,0 +1,190 @@ +// +// This file is part of ArduinoCloudThing +// +// Copyright 2021 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of ArduinoCloudThing. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to modify or +// otherwise use the software for commercial activities involving the Arduino +// software without disclosing the source code of your own applications. To purchase +// a commercial license, send an email to license@arduino.cc. +// + +#ifndef CLOUDSCHEDULER_H_ +#define CLOUDSCHEDULER_H_ + +/****************************************************************************** + INCLUDE + ******************************************************************************/ + +#include +#include "../Property.h" +#include "utility/time/TimeService.h" +#include + +/****************************************************************************** + CLASS DECLARATION + ******************************************************************************/ +enum class MaskType : int { + minute = 0, + hour = 1, + day = 2, + week = 3, /*Weekly daymask */ + month = 4, /*Day of the month 1-31 */ + year = 5 /*Month 1-12 + Day of the month 1-31 */ +}; + +class Scheduler : public TimeService { + public: + unsigned int start, end, duration; + int type; + unsigned int mask; + Scheduler(unsigned int s, unsigned int e, unsigned int d, int t, unsigned int m): start(s), end(e), duration(d), type(t), mask(m) {} + + bool isActive() { + + unsigned int now = getTime(); + if(now >= start && (now < end || end == 0)) { + /* We are in the schedule range */ + + if(type == 3 || type == 4 || type == 5) { + unsigned int nowmask = timeToMask(type, now); + if ( (nowmask & mask) == 0) { + /* This is not the correct Day or Month */ + return false; + } + } + + /* We can assume now that the schedule is always repeating with fixed delta */ + unsigned int delta = getScheduleDelta(type, mask); + if ( ( (std::max(now , start) - std::min(now , start)) % delta ) <= duration ) { + return true; + } + } + return false; + } + + Scheduler& operator=(Scheduler & aScheduler) { + start = aScheduler.start; + end = aScheduler.end; + duration = aScheduler.duration; + type = aScheduler.type; + mask = aScheduler.mask; + return *this; + } + + bool operator==(Scheduler & aScheduler) { + return start == aScheduler.start && end == aScheduler.end && duration == aScheduler.duration && type == aScheduler.type && mask == aScheduler.mask; + } + + bool operator!=(Scheduler & aScheduler) { + return !(operator==(aScheduler)); + } + private: + + unsigned int timeToMask(int type, time_t rawtime) { + struct tm * ptm; + ptm = gmtime ( &rawtime ); + + if (type == 3) { + return 1 << ptm->tm_wday; + } + + if (type == 4) { + return ptm->tm_mday; + } + + if (type == 5) { + return (tm->tm_mon << 16) | ptm->tm_mday; + } + return 0; + } + + unsigned int getScheduleDelta(int type, unsigned int mask) { + if (type == 0) { + return 60 * mask; + } + + if (type == 1) { + return 60 * 60 * mask; + } + + if (type == 2) { + return 60 * 60 * 24 * mask; + } + + if (type == 3) { + return 60 * 60 * 24; + } + + if (type == 4) { + return 60 * 60 * 24; + } + + if (type == 5) { + return 60 * 60 * 24; + } + return 0; + } +}; + +class CloudScheduler : public Property { + private: + Scheduler _value, + _cloud_value; + public: + CloudScheduler() : _value(0, 0, 0, 0, 0), _cloud_value(0, 0, 0, 0, 0) {} + CloudScheduler(unsigned int start, unsigned int end, unsigned int duration, int type, unsigned int mask) : _value(start, end, duration, type, mask), _cloud_value(start, end, duration, type, mask) {} + + virtual bool isDifferentFromCloud() { + + return _value != _cloud_value; + } + + CloudScheduler& operator=(Scheduler aScheduler) { + _value.start = aScheduler.start; + _value.end = aScheduler.end; + _value.duration = aScheduler.duration; + _value.type = aScheduler.type; + _value.mask = aScheduler.mask; + updateLocalTimestamp(); + return *this; + } + + Scheduler getCloudValue() { + return _cloud_value; + } + + Scheduler getValue() { + return _value; + } + + virtual void fromCloudToLocal() { + _value = _cloud_value; + } + virtual void fromLocalToCloud() { + _cloud_value = _value; + } + virtual CborError appendAttributesToCloud() { + CHECK_CBOR(appendAttribute(_value.start)); + CHECK_CBOR(appendAttribute(_value.end)); + CHECK_CBOR(appendAttribute(_value.duration)); + CHECK_CBOR(appendAttribute(_value.type)); + CHECK_CBOR(appendAttribute(_value.mask)); + return CborNoError; + } + virtual void setAttributesFromCloud() { + setAttribute(_cloud_value.start); + setAttribute(_cloud_value.end); + setAttribute(_cloud_value.duration); + setAttribute(_cloud_value.type); + setAttribute(_cloud_value.mask); + } +}; + +#endif /* CLOUDSCHEDULER_H_ */ From dd0ccf55df4c9536f875e9693b5ed47fa8c746d1 Mon Sep 17 00:00:00 2001 From: pennam Date: Wed, 6 Oct 2021 17:05:13 +0200 Subject: [PATCH 02/27] Initial Scheduler tests --- extras/test/CMakeLists.txt | 1 + .../test/include/Arduino_ConnectionHandler.h | 14 +++++ extras/test/src/test_CloudScheduler.cpp | 53 +++++++++++++++++++ 3 files changed, 68 insertions(+) create mode 100644 extras/test/include/Arduino_ConnectionHandler.h create mode 100644 extras/test/src/test_CloudScheduler.cpp diff --git a/extras/test/CMakeLists.txt b/extras/test/CMakeLists.txt index dd7b3e990..92b1c3a14 100644 --- a/extras/test/CMakeLists.txt +++ b/extras/test/CMakeLists.txt @@ -32,6 +32,7 @@ set(TEST_SRCS src/test_callback.cpp src/test_CloudColor.cpp src/test_CloudLocation.cpp + src/test_CloudScheduler.cpp src/test_decode.cpp src/test_encode.cpp src/test_publishEvery.cpp diff --git a/extras/test/include/Arduino_ConnectionHandler.h b/extras/test/include/Arduino_ConnectionHandler.h new file mode 100644 index 000000000..babc86f08 --- /dev/null +++ b/extras/test/include/Arduino_ConnectionHandler.h @@ -0,0 +1,14 @@ +/* + Copyright (c) 2019 Arduino. All rights reserved. +*/ + +#ifndef TEST_ARDUINO_CONNECTION_HANDLER_H_ +#define TEST_ARDUINO_CONNECTION_HANDLER_H_ + +/****************************************************************************** + TYPEDEF + ******************************************************************************/ + +typedef void ConnectionHandler; + +#endif /* TEST_ARDUINO_CONNECTION_HANDLER_H_ */ diff --git a/extras/test/src/test_CloudScheduler.cpp b/extras/test/src/test_CloudScheduler.cpp new file mode 100644 index 000000000..475dfb282 --- /dev/null +++ b/extras/test/src/test_CloudScheduler.cpp @@ -0,0 +1,53 @@ +/* + Copyright (c) 2021 Arduino. All rights reserved. +*/ + +/************************************************************************************** + INCLUDE + **************************************************************************************/ + +#include + +#include + +unsigned long time_now = 1; + +/************************************************************************************** + * TimeService Fake CTOR/DTOR + **************************************************************************************/ + +TimeService::TimeService() {} + +/************************************************************************************** + * TimeService Fake Methods + **************************************************************************************/ + +unsigned long TimeService::getTime() {return time_now;} + +/************************************************************************************** + TEST CODE + **************************************************************************************/ + +SCENARIO("Tesing cloud type 'Scheduler' Ctor", "[Scheduler::Scheduler]") +{ + WHEN("A Scheduler(0,0,0,0,0) is being instantiated") + { + Scheduler schedule(0,0,0,0,0); + THEN("The member variable 'start' should be 0") { + REQUIRE(schedule.start == 0); + } + THEN("The member variable 'end' should be 0") { + REQUIRE(schedule.end == 0); + } + THEN("The member variable 'duration' should be 0") { + REQUIRE(schedule.duration == 0); + } + THEN("The member variable 'type' should be 0") { + REQUIRE(schedule.type == 0); + } + THEN("The member variable 'mask' should be 0") { + REQUIRE(schedule.mask == 0); + } + } +} + From 5c30e04ba8f76c9f21032e68c00dd5d05abdfd56 Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 7 Oct 2021 11:30:50 +0200 Subject: [PATCH 03/27] Add tests for x minutes and weekly schedule --- extras/test/src/test_CloudScheduler.cpp | 143 ++++++++++++++++++++++++ 1 file changed, 143 insertions(+) diff --git a/extras/test/src/test_CloudScheduler.cpp b/extras/test/src/test_CloudScheduler.cpp index 475dfb282..119599b07 100644 --- a/extras/test/src/test_CloudScheduler.cpp +++ b/extras/test/src/test_CloudScheduler.cpp @@ -51,3 +51,146 @@ SCENARIO("Tesing cloud type 'Scheduler' Ctor", "[Scheduler::Scheduler]") } } +/**************************************************************************************/ + +SCENARIO("Setup a schedule that repeats each 20 minutes and test isActive Method", "[Scheduler::isActive]") +{ + Scheduler schedule(1633305600, /* Start 4/10/2021 00:00:00 */ + 1633651200, /* End 8/10/2021 00:00:00 */ + 600, /* Duration 00:10:00 */ + 0, /* Minutes */ + 20 /* Repeats 00:20:00 */ + ); + + WHEN("Time is 4/10/2021 00:00:00") + { + time_now = 1633305600; + THEN("Schedule must be active") { + REQUIRE(schedule.isActive() == true); + } + } + + WHEN("Time is 4/10/2021 00:10:00") + { + time_now = 1633306200; + THEN("Schedule must be active") { + REQUIRE(schedule.isActive() == true); + } + } + + WHEN("Time is 4/10/2021 00:10:01") + { + time_now = 1633306201; + THEN("Schedule must be inactive") { + REQUIRE(schedule.isActive() == false); + } + } + + WHEN("Time is 4/10/2021 00:19:59") + { + time_now = 1633306799; + THEN("Schedule must be inactive") { + REQUIRE(schedule.isActive() == false); + } + } + + WHEN("Time is 4/10/2021 00:20:00") + { + time_now = 1633306800; + THEN("Schedule must be active") { + REQUIRE(schedule.isActive() == true); + } + } + + WHEN("Time is 7/10/2021 23:45:00") + { + time_now = 1633650300; + THEN("Schedule must be active") { + REQUIRE(schedule.isActive() == true); + } + } + + WHEN("Time is 7/10/2021 23:55:00") + { + time_now = 1633650900; + THEN("Schedule must be inactive") { + REQUIRE(schedule.isActive() == false); + } + } + + WHEN("Time is 8/10/2021 00:00:00") + { + time_now = 1633651200; + THEN("Schedule must be inactive") { + REQUIRE(schedule.isActive() == false); + } + } + + WHEN("Time is 8/10/2021 00:05:00") + { + time_now = 1633651500; + THEN("Schedule must be inactive") { + REQUIRE(schedule.isActive() == false); + } + } +} + +/**************************************************************************************/ + +SCENARIO("Setup a weekly schedule and test isActive Method", "[Scheduler::isActive]") +{ + Scheduler schedule(1633305600, /* Start 4/10/2021 00:00:00 */ + 1633651200, /* End 8/10/2021 00:00:00 */ + 600, /* Duration 00:10:00 */ + 3, /* Weekly */ + 70 /* Daymask 1000110 */ + ); + + WHEN("Time is 4/10/2021 00:05:00") + { + time_now = 1633305900; + THEN("Schedule must be active") { + REQUIRE(schedule.isActive() == true); + } + } + + WHEN("Time is 4/10/2021 00:25:00") + { + time_now = 1633307100; + THEN("Schedule must be inactive") { + REQUIRE(schedule.isActive() == false); + } + } + + WHEN("Time is 5/10/2021 00:05:00") + { + time_now = 1633392300; + THEN("Schedule must be active") { + REQUIRE(schedule.isActive() == true); + } + } + + WHEN("Time is 5/10/2021 00:25:00") + { + time_now = 1633393500; + THEN("Schedule must be inactive") { + REQUIRE(schedule.isActive() == false); + } + } + + WHEN("Time is 6/10/2021 00:05:00") + { + time_now = 1633478700; + THEN("Schedule must be inactive") { + REQUIRE(schedule.isActive() == false); + } + } + + WHEN("Time is 7/10/2021 00:05:00") + { + time_now = 1633565100; + THEN("Schedule must be inactive") { + REQUIRE(schedule.isActive() == false); + } + } +} From e8273838d8b87099e8a277ca9a652a1b91d7a9a8 Mon Sep 17 00:00:00 2001 From: pennam Date: Tue, 26 Oct 2021 13:20:08 +0200 Subject: [PATCH 04/27] Scheduler property refactoring --- extras/test/src/test_CloudScheduler.cpp | 15 +- src/property/types/CloudScheduler.h | 228 ++++++++++++++++++------ 2 files changed, 180 insertions(+), 63 deletions(-) diff --git a/extras/test/src/test_CloudScheduler.cpp b/extras/test/src/test_CloudScheduler.cpp index 119599b07..530a54c6a 100644 --- a/extras/test/src/test_CloudScheduler.cpp +++ b/extras/test/src/test_CloudScheduler.cpp @@ -30,9 +30,9 @@ unsigned long TimeService::getTime() {return time_now;} SCENARIO("Tesing cloud type 'Scheduler' Ctor", "[Scheduler::Scheduler]") { - WHEN("A Scheduler(0,0,0,0,0) is being instantiated") + WHEN("A Scheduler(0,0,0,0) is being instantiated") { - Scheduler schedule(0,0,0,0,0); + Scheduler schedule(0,0,0,0); THEN("The member variable 'start' should be 0") { REQUIRE(schedule.start == 0); } @@ -42,9 +42,6 @@ SCENARIO("Tesing cloud type 'Scheduler' Ctor", "[Scheduler::Scheduler]") THEN("The member variable 'duration' should be 0") { REQUIRE(schedule.duration == 0); } - THEN("The member variable 'type' should be 0") { - REQUIRE(schedule.type == 0); - } THEN("The member variable 'mask' should be 0") { REQUIRE(schedule.mask == 0); } @@ -58,8 +55,8 @@ SCENARIO("Setup a schedule that repeats each 20 minutes and test isActive Method Scheduler schedule(1633305600, /* Start 4/10/2021 00:00:00 */ 1633651200, /* End 8/10/2021 00:00:00 */ 600, /* Duration 00:10:00 */ - 0, /* Minutes */ - 20 /* Repeats 00:20:00 */ + 1140850708 /* Minutes */ + /* Repeats 00:20:00 */ ); WHEN("Time is 4/10/2021 00:00:00") @@ -142,8 +139,8 @@ SCENARIO("Setup a weekly schedule and test isActive Method", "[Scheduler::isActi Scheduler schedule(1633305600, /* Start 4/10/2021 00:00:00 */ 1633651200, /* End 8/10/2021 00:00:00 */ 600, /* Duration 00:10:00 */ - 3, /* Weekly */ - 70 /* Daymask 1000110 */ + 134217798 /* Weekly */ + /* Daymask 1000110 */ ); WHEN("Time is 4/10/2021 00:05:00") diff --git a/src/property/types/CloudScheduler.h b/src/property/types/CloudScheduler.h index 97d6f45fe..c0d258a93 100644 --- a/src/property/types/CloudScheduler.h +++ b/src/property/types/CloudScheduler.h @@ -30,41 +30,25 @@ /****************************************************************************** CLASS DECLARATION ******************************************************************************/ -enum class MaskType : int { - minute = 0, - hour = 1, - day = 2, - week = 3, /*Weekly daymask */ - month = 4, /*Day of the month 1-31 */ - year = 5 /*Month 1-12 + Day of the month 1-31 */ -}; - class Scheduler : public TimeService { public: - unsigned int start, end, duration; - int type; - unsigned int mask; - Scheduler(unsigned int s, unsigned int e, unsigned int d, int t, unsigned int m): start(s), end(e), duration(d), type(t), mask(m) {} + unsigned int start, end, duration, mask; + Scheduler(unsigned int s, unsigned int e, unsigned int d, unsigned int m): start(s), end(e), duration(d), mask(m) {} bool isActive() { unsigned int now = getTime(); - if(now >= start && (now < end || end == 0)) { + if(checkSchedulePeriod(now, start, end)) { /* We are in the schedule range */ - if(type == 3 || type == 4 || type == 5) { - unsigned int nowmask = timeToMask(type, now); - if ( (nowmask & mask) == 0) { - /* This is not the correct Day or Month */ - return false; + if(checkScheduleMask(now, mask)) { + + /* We can assume now that the schedule is always repeating with fixed delta */ + unsigned int delta = getScheduleDelta(mask); + if ( ( (std::max(now , start) - std::min(now , start)) % delta ) <= duration ) { + return true; } } - - /* We can assume now that the schedule is always repeating with fixed delta */ - unsigned int delta = getScheduleDelta(type, mask); - if ( ( (std::max(now , start) - std::min(now , start)) % delta ) <= duration ) { - return true; - } } return false; } @@ -73,62 +57,201 @@ class Scheduler : public TimeService { start = aScheduler.start; end = aScheduler.end; duration = aScheduler.duration; - type = aScheduler.type; mask = aScheduler.mask; return *this; } bool operator==(Scheduler & aScheduler) { - return start == aScheduler.start && end == aScheduler.end && duration == aScheduler.duration && type == aScheduler.type && mask == aScheduler.mask; + return start == aScheduler.start && end == aScheduler.end && duration == aScheduler.duration && mask == aScheduler.mask; } bool operator!=(Scheduler & aScheduler) { return !(operator==(aScheduler)); } private: + bool isScheduleOneShot(unsigned int mask) { + if((mask & 0x3C000000) == 0x00000000) { + return true; + } else { + return false; + } + } - unsigned int timeToMask(int type, time_t rawtime) { - struct tm * ptm; - ptm = gmtime ( &rawtime ); + bool isScheduleFixed(unsigned int mask) { + if((mask & 0x3C000000) == 0x04000000) { + return true; + } else { + return false; + } + } - if (type == 3) { - return 1 << ptm->tm_wday; + bool isScheduleWeekly(unsigned int mask) { + if((mask & 0x3C000000) == 0x08000000) { + return true; + } else { + return false; } + } - if (type == 4) { - return ptm->tm_mday; + bool isScheduleMonthly(unsigned int mask) { + if((mask & 0x3C000000) == 0x0C000000) { + return true; + } else { + return false; } + } - if (type == 5) { - return (tm->tm_mon << 16) | ptm->tm_mday; + bool isScheduleYearly(unsigned int mask) { + if((mask & 0x3C000000) == 0x10000000) { + return true; + } else { + return false; } - return 0; } - unsigned int getScheduleDelta(int type, unsigned int mask) { - if (type == 0) { - return 60 * mask; + bool isScheduleInSeconds(unsigned int mask) { + if((mask & 0xC0000000) == 0x00000000) { + return true; + } else { + return false; } + } - if (type == 1) { - return 60 * 60 * mask; + bool isScheduleInMinutes(unsigned int mask) { + if((mask & 0xC0000000) == 0x40000000) { + return true; + } else { + return false; } + } - if (type == 2) { - return 60 * 60 * 24 * mask; + bool isScheduleInHours(unsigned int mask) { + if((mask & 0xC0000000) == 0x80000000) { + return true; + } else { + return false; } + } - if (type == 3) { - return 60 * 60 * 24; + bool isScheduleInDays(unsigned int mask) { + if((mask & 0xC0000000) == 0xC0000000) { + return true; + } else { + return false; } + } - if (type == 4) { - return 60 * 60 * 24; + unsigned int timeToWeekMask(time_t rawtime) { + struct tm * ptm; + ptm = gmtime ( &rawtime ); + + return 1 << ptm->tm_wday; + } + + unsigned int timeToDay(time_t rawtime) { + struct tm * ptm; + ptm = gmtime ( &rawtime ); + + return ptm->tm_mday; + } + + unsigned int timeToMonth(time_t rawtime) { + struct tm * ptm; + ptm = gmtime ( &rawtime ); + + return ptm->tm_mon; + } + + unsigned int getScheduleRawMask(unsigned int mask) { + return mask & 0x03FFFFFF; + } + + unsigned int getScheduleWeekMask(unsigned int mask) { + return mask & 0x000000FF; + } + + unsigned int getScheduleDay(unsigned int mask) { + return mask & 0x000000FF; + } + + unsigned int getScheduleMonth(unsigned int mask) { + return (mask & 0x0000FF00) >> 8; + } + + bool checkSchedulePeriod(unsigned int now, unsigned int start, unsigned int end) { + if(now >= start && (now < end || end == 0)) { + return true; + } else { + return false; + } + } + + bool checkScheduleMask(unsigned int now, unsigned int mask) { + if(isScheduleFixed(mask) || isScheduleOneShot(mask)) { + return true; + } + + if(isScheduleWeekly(mask)) { + unsigned int nowMask = timeToWeekMask(now); + unsigned int scheduleMask = getScheduleWeekMask(mask); + + if((nowMask & scheduleMask) == 0) { + return false; + } else { + return true; + } + } + + if(isScheduleMonthly(mask)) { + unsigned int nowDay = timeToDay(now); + unsigned int scheduleDay = getScheduleDay(mask); + + if(nowDay != scheduleDay) { + return false; + } else { + return true; + } + } + + if(isScheduleYearly(mask)) { + unsigned int nowDay = timeToDay(now); + unsigned int scheduleDay = getScheduleDay(mask); + unsigned int nowMonth = timeToMonth(now); + unsigned int scheduleMonth = getScheduleMonth(mask); + + if((nowDay != scheduleDay) || (nowMonth != scheduleMonth)) { + return false; + } else { + return true; + } + } + + return false; + } + + unsigned int getScheduleDelta(unsigned int mask) { + if(isScheduleOneShot(mask)) { + return 0xFFFFFFFF; } + + if(isScheduleFixed(mask)) { + if(isScheduleInSeconds(mask)) { + return getScheduleRawMask(mask); + } + + if(isScheduleInMinutes(mask)) { + return 60 * getScheduleRawMask(mask); + } - if (type == 5) { + if(isScheduleInHours(mask)) { + return 60 * 60 * getScheduleRawMask(mask); + } + } + + if(isScheduleWeekly(mask) || isScheduleMonthly(mask) || isScheduleYearly(mask)) { return 60 * 60 * 24; } + return 0; } }; @@ -138,8 +261,8 @@ class CloudScheduler : public Property { Scheduler _value, _cloud_value; public: - CloudScheduler() : _value(0, 0, 0, 0, 0), _cloud_value(0, 0, 0, 0, 0) {} - CloudScheduler(unsigned int start, unsigned int end, unsigned int duration, int type, unsigned int mask) : _value(start, end, duration, type, mask), _cloud_value(start, end, duration, type, mask) {} + CloudScheduler() : _value(0, 0, 0, 0), _cloud_value(0, 0, 0, 0) {} + CloudScheduler(unsigned int start, unsigned int end, unsigned int duration, unsigned int mask) : _value(start, end, duration, mask), _cloud_value(start, end, duration, mask) {} virtual bool isDifferentFromCloud() { @@ -150,7 +273,6 @@ class CloudScheduler : public Property { _value.start = aScheduler.start; _value.end = aScheduler.end; _value.duration = aScheduler.duration; - _value.type = aScheduler.type; _value.mask = aScheduler.mask; updateLocalTimestamp(); return *this; @@ -174,7 +296,6 @@ class CloudScheduler : public Property { CHECK_CBOR(appendAttribute(_value.start)); CHECK_CBOR(appendAttribute(_value.end)); CHECK_CBOR(appendAttribute(_value.duration)); - CHECK_CBOR(appendAttribute(_value.type)); CHECK_CBOR(appendAttribute(_value.mask)); return CborNoError; } @@ -182,7 +303,6 @@ class CloudScheduler : public Property { setAttribute(_cloud_value.start); setAttribute(_cloud_value.end); setAttribute(_cloud_value.duration); - setAttribute(_cloud_value.type); setAttribute(_cloud_value.mask); } }; From a3a739e57d22759461bf0258dde33ef7ce975ecc Mon Sep 17 00:00:00 2001 From: pennam Date: Tue, 26 Oct 2021 14:09:46 +0200 Subject: [PATCH 05/27] Add monthly yearly and oneshot schedule tests --- extras/test/src/test_CloudScheduler.cpp | 316 ++++++++++++++++++++++++ 1 file changed, 316 insertions(+) diff --git a/extras/test/src/test_CloudScheduler.cpp b/extras/test/src/test_CloudScheduler.cpp index 530a54c6a..a505cea15 100644 --- a/extras/test/src/test_CloudScheduler.cpp +++ b/extras/test/src/test_CloudScheduler.cpp @@ -191,3 +191,319 @@ SCENARIO("Setup a weekly schedule and test isActive Method", "[Scheduler::isActi } } } + +/**************************************************************************************/ + +SCENARIO("Setup a monthly schedule and test isActive Method", "[Scheduler::isActive]") +{ + Scheduler schedule(1633305600, /* Start 4/10/2021 00:00:00 */ + 1664841600, /* End 4/10/2022 00:00:00 */ + 600, /* Duration 00:10:00 */ + 201326598 /* Monthly */ + /* Day of month 6 */ + ); + + WHEN("Time is 6/09/2021 00:05:00") + { + time_now = 1630886700; + THEN("Schedule must be inactive") { + REQUIRE(schedule.isActive() == false); + } + } + + WHEN("Time is 6/10/2021 00:05:00") + { + time_now = 1633478700; + THEN("Schedule must be active") { + REQUIRE(schedule.isActive() == true); + } + } + + WHEN("Time is 6/10/2021 00:25:00") + { + time_now = 1633479900; + THEN("Schedule must be inactive") { + REQUIRE(schedule.isActive() == false); + } + } + + WHEN("Time is 6/11/2021 00:05:00") + { + time_now = 1636157100; + THEN("Schedule must be active") { + REQUIRE(schedule.isActive() == true); + } + } + + WHEN("Time is 6/11/2021 00:25:00") + { + time_now = 1636158300; + THEN("Schedule must be inactive") { + REQUIRE(schedule.isActive() == false); + } + } + + WHEN("Time is 7/11/2021 00:05:00") + { + time_now = 1636243500; + THEN("Schedule must be inactive") { + REQUIRE(schedule.isActive() == false); + } + } + + WHEN("Time is 6/12/2021 00:05:00") + { + time_now = 1638749100; + THEN("Schedule must be active") { + REQUIRE(schedule.isActive() == true); + } + } + + WHEN("Time is 6/01/2022 00:05:00") + { + time_now = 1641427500; + THEN("Schedule must be active") { + REQUIRE(schedule.isActive() == true); + } + } + + WHEN("Time is 6/02/2022 00:05:00") + { + time_now = 1644105900; + THEN("Schedule must be active") { + REQUIRE(schedule.isActive() == true); + } + } + + WHEN("Time is 6/03/2022 00:05:00") + { + time_now = 1646525100; + THEN("Schedule must be active") { + REQUIRE(schedule.isActive() == true); + } + } + + WHEN("Time is 6/04/2022 00:05:00") + { + time_now = 1649203500; + THEN("Schedule must be active") { + REQUIRE(schedule.isActive() == true); + } + } + + WHEN("Time is 6/05/2022 00:05:00") + { + time_now = 1651795500; + THEN("Schedule must be active") { + REQUIRE(schedule.isActive() == true); + } + } + + WHEN("Time is 6/06/2022 00:05:00") + { + time_now = 1654473900; + THEN("Schedule must be active") { + REQUIRE(schedule.isActive() == true); + } + } + + WHEN("Time is 6/07/2022 00:05:00") + { + time_now = 1657065900; + THEN("Schedule must be active") { + REQUIRE(schedule.isActive() == true); + } + } + + WHEN("Time is 6/08/2022 00:05:00") + { + time_now = 1659744300; + THEN("Schedule must be active") { + REQUIRE(schedule.isActive() == true); + } + } + + WHEN("Time is 6/09/2022 00:05:00") + { + time_now = 1662422700; + THEN("Schedule must be active") { + REQUIRE(schedule.isActive() == true); + } + } + + WHEN("Time is 6/10/2022 00:05:00") + { + time_now = 1665014700; + THEN("Schedule must be inactive") { + REQUIRE(schedule.isActive() == false); + } + } +} + +/**************************************************************************************/ + +SCENARIO("Setup a yearly schedule and test isActive Method", "[Scheduler::isActive]") +{ + Scheduler schedule(1633305600, /* Start 4/10/2021 00:00:00 */ + 1759536000, /* End 4/10/2025 00:00:00 */ + 600, /* Duration 00:10:00 */ + 268438022 /* Yearly */ + /* Month 11, Day of month 6 */ + ); + + WHEN("Time is 6/11/2020 00:05:00") + { + time_now = 1604621100; + THEN("Schedule must be inactive") { + REQUIRE(schedule.isActive() == false); + } + } + + WHEN("Time is 6/11/2021 00:05:00") + { + time_now = 1636157100; + THEN("Schedule must be active") { + REQUIRE(schedule.isActive() == true); + } + } + + WHEN("Time is 6/11/2021 00:25:00") + { + time_now = 1636158300; + THEN("Schedule must be inactive") { + REQUIRE(schedule.isActive() == false); + } + } + + WHEN("Time is 6/11/2022 00:05:00") + { + time_now = 1667693100; + THEN("Schedule must be active") { + REQUIRE(schedule.isActive() == true); + } + } + + WHEN("Time is 6/11/2022 00:25:00") + { + time_now = 1667694300; + THEN("Schedule must be inactive") { + REQUIRE(schedule.isActive() == false); + } + } + + WHEN("Time is 7/11/2021 00:05:00") + { + time_now = 1636243500; + THEN("Schedule must be inactive") { + REQUIRE(schedule.isActive() == false); + } + } + + WHEN("Time is 6/11/2023 00:05:00") + { + time_now = 1699229100; + THEN("Schedule must be active") { + REQUIRE(schedule.isActive() == true); + } + } + + WHEN("Time is 6/11/2024 00:05:00") + { + time_now = 1730851500; + THEN("Schedule must be active") { + REQUIRE(schedule.isActive() == true); + } + } + + WHEN("Time is 6/11/2025 00:05:00") + { + time_now = 1762387500; + THEN("Schedule must be inactive") { + REQUIRE(schedule.isActive() == false); + } + } +} + +/**************************************************************************************/ + +SCENARIO("Setup a one shot schedule and test isActive Method", "[Scheduler::isActive]") +{ + Scheduler schedule(1636156800, /* Start 6/11/2021 00:00:00 */ + 1636243199, /* End 6/11/2021 23:59:59 */ + 600, /* Duration 00:10:00 */ + 0 /* One shot */ + ); + + WHEN("Time is 6/11/2020 00:05:00") + { + time_now = 1604621100; + THEN("Schedule must be inactive") { + REQUIRE(schedule.isActive() == false); + } + } + + WHEN("Time is 6/11/2021 00:05:00") + { + time_now = 1636157100; + THEN("Schedule must be active") { + REQUIRE(schedule.isActive() == true); + } + } + + WHEN("Time is 6/11/2021 00:25:00") + { + time_now = 1636158300; + THEN("Schedule must be inactive") { + REQUIRE(schedule.isActive() == false); + } + } + + WHEN("Time is 6/11/2022 00:05:00") + { + time_now = 1667693100; + THEN("Schedule must be inactive") { + REQUIRE(schedule.isActive() == false); + } + } + + WHEN("Time is 7/11/2021 00:05:00") + { + time_now = 1636243500; + THEN("Schedule must be inactive") { + REQUIRE(schedule.isActive() == false); + } + } + + WHEN("Time is 7/11/2021 00:15:00") + { + time_now = 1636244100; + THEN("Schedule must be inactive") { + REQUIRE(schedule.isActive() == false); + } + } + + WHEN("Time is 6/11/2021 00:11:00") + { + time_now = 1636157460; + THEN("Schedule must be inactive") { + REQUIRE(schedule.isActive() == false); + } + } + + WHEN("Time is 6/11/2021 00:01:00") + { + time_now = 1636156860; + THEN("Schedule must be active") { + REQUIRE(schedule.isActive() == true); + } + } + + WHEN("Time is 7/11/2021 00:11:00") + { + time_now = 1636243860; + THEN("Schedule must be inactive") { + REQUIRE(schedule.isActive() == false); + } + } +} + From a8e1a772f46536c43d1e328ef09c65bae84b174b Mon Sep 17 00:00:00 2001 From: pennam Date: Wed, 27 Oct 2021 10:20:57 +0200 Subject: [PATCH 06/27] Fix typo in comment --- extras/test/src/test_decode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extras/test/src/test_decode.cpp b/extras/test/src/test_decode.cpp index c95d4afe9..d67afd440 100644 --- a/extras/test/src/test_decode.cpp +++ b/extras/test/src/test_decode.cpp @@ -143,7 +143,7 @@ SCENARIO("Arduino Cloud Properties are decoded", "[ArduinoCloudThing::decode]") CloudLocation location_test = CloudLocation(0, 1); addPropertyToContainer(property_container, location_test, "test", Permission::ReadWrite); - /* [{0: "test:lat", 3: 2},{0: "test:lon", 3: 3}] = 82 A2 00 68 74 65 73 74 3A 6C 61 74 02 02 A2 00 68 74 65 73 74 3A 6C 6F 6E 02 03*/ + /* [{0: "test:lat", 2: 2},{0: "test:lon", 2: 3}] = 82 A2 00 68 74 65 73 74 3A 6C 61 74 02 02 A2 00 68 74 65 73 74 3A 6C 6F 6E 02 03*/ uint8_t const payload[] = { 0x82, 0xA2, 0x00, 0x68, 0x74, 0x65, 0x73, 0x74, 0x3A, 0x6C, 0x61, 0x74, 0x02, 0x02, 0xA2, 0x00, 0x68, 0x74, 0x65, 0x73, 0x74, 0x3A, 0x6C, 0x6F, 0x6E, 0x02, 0x03 }; CBORDecoder::decode(property_container, payload, sizeof(payload) / sizeof(uint8_t)); Location location_compare = Location(2, 3); From 116851fe7bfff94cb7864bc9db05520fc9c71c03 Mon Sep 17 00:00:00 2001 From: pennam Date: Wed, 27 Oct 2021 10:46:49 +0200 Subject: [PATCH 07/27] Rename property Scheduler/CloudScheduler to Schedule/CloudSchedule --- extras/test/CMakeLists.txt | 2 +- ...udScheduler.cpp => test_CloudSchedule.cpp} | 28 +++++------ src/property/PropertyContainer.h | 2 +- .../{CloudScheduler.h => CloudSchedule.h} | 50 +++++++++---------- 4 files changed, 41 insertions(+), 41 deletions(-) rename extras/test/src/{test_CloudScheduler.cpp => test_CloudSchedule.cpp} (94%) rename src/property/types/{CloudScheduler.h => CloudSchedule.h} (84%) diff --git a/extras/test/CMakeLists.txt b/extras/test/CMakeLists.txt index 92b1c3a14..a2b9c749e 100644 --- a/extras/test/CMakeLists.txt +++ b/extras/test/CMakeLists.txt @@ -32,7 +32,7 @@ set(TEST_SRCS src/test_callback.cpp src/test_CloudColor.cpp src/test_CloudLocation.cpp - src/test_CloudScheduler.cpp + src/test_CloudSchedule.cpp src/test_decode.cpp src/test_encode.cpp src/test_publishEvery.cpp diff --git a/extras/test/src/test_CloudScheduler.cpp b/extras/test/src/test_CloudSchedule.cpp similarity index 94% rename from extras/test/src/test_CloudScheduler.cpp rename to extras/test/src/test_CloudSchedule.cpp index a505cea15..e8d307e2b 100644 --- a/extras/test/src/test_CloudScheduler.cpp +++ b/extras/test/src/test_CloudSchedule.cpp @@ -8,7 +8,7 @@ #include -#include +#include unsigned long time_now = 1; @@ -28,11 +28,11 @@ unsigned long TimeService::getTime() {return time_now;} TEST CODE **************************************************************************************/ -SCENARIO("Tesing cloud type 'Scheduler' Ctor", "[Scheduler::Scheduler]") +SCENARIO("Tesing cloud type 'Schedule' Ctor", "[Schedule::Schedule]") { - WHEN("A Scheduler(0,0,0,0) is being instantiated") + WHEN("A Schedule(0,0,0,0) is being instantiated") { - Scheduler schedule(0,0,0,0); + Schedule schedule(0,0,0,0); THEN("The member variable 'start' should be 0") { REQUIRE(schedule.start == 0); } @@ -50,9 +50,9 @@ SCENARIO("Tesing cloud type 'Scheduler' Ctor", "[Scheduler::Scheduler]") /**************************************************************************************/ -SCENARIO("Setup a schedule that repeats each 20 minutes and test isActive Method", "[Scheduler::isActive]") +SCENARIO("Setup a schedule that repeats each 20 minutes and test isActive Method", "[Schedule::isActive]") { - Scheduler schedule(1633305600, /* Start 4/10/2021 00:00:00 */ + Schedule schedule(1633305600, /* Start 4/10/2021 00:00:00 */ 1633651200, /* End 8/10/2021 00:00:00 */ 600, /* Duration 00:10:00 */ 1140850708 /* Minutes */ @@ -134,9 +134,9 @@ SCENARIO("Setup a schedule that repeats each 20 minutes and test isActive Method /**************************************************************************************/ -SCENARIO("Setup a weekly schedule and test isActive Method", "[Scheduler::isActive]") +SCENARIO("Setup a weekly schedule and test isActive Method", "[Schedule::isActive]") { - Scheduler schedule(1633305600, /* Start 4/10/2021 00:00:00 */ + Schedule schedule(1633305600, /* Start 4/10/2021 00:00:00 */ 1633651200, /* End 8/10/2021 00:00:00 */ 600, /* Duration 00:10:00 */ 134217798 /* Weekly */ @@ -194,9 +194,9 @@ SCENARIO("Setup a weekly schedule and test isActive Method", "[Scheduler::isActi /**************************************************************************************/ -SCENARIO("Setup a monthly schedule and test isActive Method", "[Scheduler::isActive]") +SCENARIO("Setup a monthly schedule and test isActive Method", "[Schedule::isActive]") { - Scheduler schedule(1633305600, /* Start 4/10/2021 00:00:00 */ + Schedule schedule(1633305600, /* Start 4/10/2021 00:00:00 */ 1664841600, /* End 4/10/2022 00:00:00 */ 600, /* Duration 00:10:00 */ 201326598 /* Monthly */ @@ -342,9 +342,9 @@ SCENARIO("Setup a monthly schedule and test isActive Method", "[Scheduler::isAct /**************************************************************************************/ -SCENARIO("Setup a yearly schedule and test isActive Method", "[Scheduler::isActive]") +SCENARIO("Setup a yearly schedule and test isActive Method", "[Schedule::isActive]") { - Scheduler schedule(1633305600, /* Start 4/10/2021 00:00:00 */ + Schedule schedule(1633305600, /* Start 4/10/2021 00:00:00 */ 1759536000, /* End 4/10/2025 00:00:00 */ 600, /* Duration 00:10:00 */ 268438022 /* Yearly */ @@ -426,9 +426,9 @@ SCENARIO("Setup a yearly schedule and test isActive Method", "[Scheduler::isActi /**************************************************************************************/ -SCENARIO("Setup a one shot schedule and test isActive Method", "[Scheduler::isActive]") +SCENARIO("Setup a one shot schedule and test isActive Method", "[Schedule::isActive]") { - Scheduler schedule(1636156800, /* Start 6/11/2021 00:00:00 */ + Schedule schedule(1636156800, /* Start 6/11/2021 00:00:00 */ 1636243199, /* End 6/11/2021 23:59:59 */ 600, /* Duration 00:10:00 */ 0 /* One shot */ diff --git a/src/property/PropertyContainer.h b/src/property/PropertyContainer.h index 65882afe4..8c254875e 100644 --- a/src/property/PropertyContainer.h +++ b/src/property/PropertyContainer.h @@ -40,7 +40,7 @@ #include "types/CloudUnsignedInt.h" #include "types/CloudString.h" #include "types/CloudLocation.h" -#include "types/CloudScheduler.h" +#include "types/CloudSchedule.h" #include "types/CloudColor.h" #include "types/CloudWrapperBase.h" diff --git a/src/property/types/CloudScheduler.h b/src/property/types/CloudSchedule.h similarity index 84% rename from src/property/types/CloudScheduler.h rename to src/property/types/CloudSchedule.h index c0d258a93..a5ecaf288 100644 --- a/src/property/types/CloudScheduler.h +++ b/src/property/types/CloudSchedule.h @@ -15,8 +15,8 @@ // a commercial license, send an email to license@arduino.cc. // -#ifndef CLOUDSCHEDULER_H_ -#define CLOUDSCHEDULER_H_ +#ifndef CLOUDSCHEDULE_H_ +#define CLOUDSCHEDULE_H_ /****************************************************************************** INCLUDE @@ -30,10 +30,10 @@ /****************************************************************************** CLASS DECLARATION ******************************************************************************/ -class Scheduler : public TimeService { +class Schedule : public TimeService { public: unsigned int start, end, duration, mask; - Scheduler(unsigned int s, unsigned int e, unsigned int d, unsigned int m): start(s), end(e), duration(d), mask(m) {} + Schedule(unsigned int s, unsigned int e, unsigned int d, unsigned int m): start(s), end(e), duration(d), mask(m) {} bool isActive() { @@ -53,20 +53,20 @@ class Scheduler : public TimeService { return false; } - Scheduler& operator=(Scheduler & aScheduler) { - start = aScheduler.start; - end = aScheduler.end; - duration = aScheduler.duration; - mask = aScheduler.mask; + Schedule& operator=(Schedule & aSchedule) { + start = aSchedule.start; + end = aSchedule.end; + duration = aSchedule.duration; + mask = aSchedule.mask; return *this; } - bool operator==(Scheduler & aScheduler) { - return start == aScheduler.start && end == aScheduler.end && duration == aScheduler.duration && mask == aScheduler.mask; + bool operator==(Schedule & aSchedule) { + return start == aSchedule.start && end == aSchedule.end && duration == aSchedule.duration && mask == aSchedule.mask; } - bool operator!=(Scheduler & aScheduler) { - return !(operator==(aScheduler)); + bool operator!=(Schedule & aSchedule) { + return !(operator==(aSchedule)); } private: bool isScheduleOneShot(unsigned int mask) { @@ -256,33 +256,33 @@ class Scheduler : public TimeService { } }; -class CloudScheduler : public Property { +class CloudSchedule : public Property { private: - Scheduler _value, + Schedule _value, _cloud_value; public: - CloudScheduler() : _value(0, 0, 0, 0), _cloud_value(0, 0, 0, 0) {} - CloudScheduler(unsigned int start, unsigned int end, unsigned int duration, unsigned int mask) : _value(start, end, duration, mask), _cloud_value(start, end, duration, mask) {} + CloudSchedule() : _value(0, 0, 0, 0), _cloud_value(0, 0, 0, 0) {} + CloudSchedule(unsigned int start, unsigned int end, unsigned int duration, unsigned int mask) : _value(start, end, duration, mask), _cloud_value(start, end, duration, mask) {} virtual bool isDifferentFromCloud() { return _value != _cloud_value; } - CloudScheduler& operator=(Scheduler aScheduler) { - _value.start = aScheduler.start; - _value.end = aScheduler.end; - _value.duration = aScheduler.duration; - _value.mask = aScheduler.mask; + CloudSchedule& operator=(Schedule aSchedule) { + _value.start = aSchedule.start; + _value.end = aSchedule.end; + _value.duration = aSchedule.duration; + _value.mask = aSchedule.mask; updateLocalTimestamp(); return *this; } - Scheduler getCloudValue() { + Schedule getCloudValue() { return _cloud_value; } - Scheduler getValue() { + Schedule getValue() { return _value; } @@ -307,4 +307,4 @@ class CloudScheduler : public Property { } }; -#endif /* CLOUDSCHEDULER_H_ */ +#endif /* CLOUDSCHEDULE_H_ */ From b75b8cdc8bb727baa23fb5734b08b019b4add872 Mon Sep 17 00:00:00 2001 From: pennam Date: Wed, 27 Oct 2021 17:14:42 +0200 Subject: [PATCH 08/27] Add isActive method to CloudSchedule --- src/property/types/CloudSchedule.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/property/types/CloudSchedule.h b/src/property/types/CloudSchedule.h index a5ecaf288..83de15c34 100644 --- a/src/property/types/CloudSchedule.h +++ b/src/property/types/CloudSchedule.h @@ -286,6 +286,10 @@ class CloudSchedule : public Property { return _value; } + bool isActive() { + return _value.isActive(); + } + virtual void fromCloudToLocal() { _value = _cloud_value; } From 76647d94f2aa6facebc6e5847a58fffa39c8debf Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 28 Oct 2021 11:02:11 +0200 Subject: [PATCH 09/27] Rename CloudSchedule fields from start end duration mask to frm to len msk --- extras/test/src/test_CloudSchedule.cpp | 26 ++--- src/property/types/CloudSchedule.h | 144 ++++++++++++------------- 2 files changed, 85 insertions(+), 85 deletions(-) diff --git a/extras/test/src/test_CloudSchedule.cpp b/extras/test/src/test_CloudSchedule.cpp index e8d307e2b..aba4aad0f 100644 --- a/extras/test/src/test_CloudSchedule.cpp +++ b/extras/test/src/test_CloudSchedule.cpp @@ -33,17 +33,17 @@ SCENARIO("Tesing cloud type 'Schedule' Ctor", "[Schedule::Schedule]") WHEN("A Schedule(0,0,0,0) is being instantiated") { Schedule schedule(0,0,0,0); - THEN("The member variable 'start' should be 0") { - REQUIRE(schedule.start == 0); + THEN("The member variable 'frm' should be 0") { + REQUIRE(schedule.frm == 0); } - THEN("The member variable 'end' should be 0") { - REQUIRE(schedule.end == 0); + THEN("The member variable 'to' should be 0") { + REQUIRE(schedule.to == 0); } - THEN("The member variable 'duration' should be 0") { - REQUIRE(schedule.duration == 0); + THEN("The member variable 'len' should be 0") { + REQUIRE(schedule.len == 0); } - THEN("The member variable 'mask' should be 0") { - REQUIRE(schedule.mask == 0); + THEN("The member variable 'msk' should be 0") { + REQUIRE(schedule.msk == 0); } } } @@ -52,7 +52,7 @@ SCENARIO("Tesing cloud type 'Schedule' Ctor", "[Schedule::Schedule]") SCENARIO("Setup a schedule that repeats each 20 minutes and test isActive Method", "[Schedule::isActive]") { - Schedule schedule(1633305600, /* Start 4/10/2021 00:00:00 */ + Schedule schedule( 1633305600, /* Start 4/10/2021 00:00:00 */ 1633651200, /* End 8/10/2021 00:00:00 */ 600, /* Duration 00:10:00 */ 1140850708 /* Minutes */ @@ -136,7 +136,7 @@ SCENARIO("Setup a schedule that repeats each 20 minutes and test isActive Method SCENARIO("Setup a weekly schedule and test isActive Method", "[Schedule::isActive]") { - Schedule schedule(1633305600, /* Start 4/10/2021 00:00:00 */ + Schedule schedule( 1633305600, /* Start 4/10/2021 00:00:00 */ 1633651200, /* End 8/10/2021 00:00:00 */ 600, /* Duration 00:10:00 */ 134217798 /* Weekly */ @@ -196,7 +196,7 @@ SCENARIO("Setup a weekly schedule and test isActive Method", "[Schedule::isActiv SCENARIO("Setup a monthly schedule and test isActive Method", "[Schedule::isActive]") { - Schedule schedule(1633305600, /* Start 4/10/2021 00:00:00 */ + Schedule schedule( 1633305600, /* Start 4/10/2021 00:00:00 */ 1664841600, /* End 4/10/2022 00:00:00 */ 600, /* Duration 00:10:00 */ 201326598 /* Monthly */ @@ -344,7 +344,7 @@ SCENARIO("Setup a monthly schedule and test isActive Method", "[Schedule::isActi SCENARIO("Setup a yearly schedule and test isActive Method", "[Schedule::isActive]") { - Schedule schedule(1633305600, /* Start 4/10/2021 00:00:00 */ + Schedule schedule( 1633305600, /* Start 4/10/2021 00:00:00 */ 1759536000, /* End 4/10/2025 00:00:00 */ 600, /* Duration 00:10:00 */ 268438022 /* Yearly */ @@ -428,7 +428,7 @@ SCENARIO("Setup a yearly schedule and test isActive Method", "[Schedule::isActiv SCENARIO("Setup a one shot schedule and test isActive Method", "[Schedule::isActive]") { - Schedule schedule(1636156800, /* Start 6/11/2021 00:00:00 */ + Schedule schedule( 1636156800, /* Start 6/11/2021 00:00:00 */ 1636243199, /* End 6/11/2021 23:59:59 */ 600, /* Duration 00:10:00 */ 0 /* One shot */ diff --git a/src/property/types/CloudSchedule.h b/src/property/types/CloudSchedule.h index 83de15c34..fc018b15f 100644 --- a/src/property/types/CloudSchedule.h +++ b/src/property/types/CloudSchedule.h @@ -32,20 +32,20 @@ ******************************************************************************/ class Schedule : public TimeService { public: - unsigned int start, end, duration, mask; - Schedule(unsigned int s, unsigned int e, unsigned int d, unsigned int m): start(s), end(e), duration(d), mask(m) {} + unsigned int frm, to, len, msk; + Schedule(unsigned int s, unsigned int e, unsigned int d, unsigned int m): frm(s), to(e), len(d), msk(m) {} bool isActive() { unsigned int now = getTime(); - if(checkSchedulePeriod(now, start, end)) { + if(checkSchedulePeriod(now, frm, to)) { /* We are in the schedule range */ - if(checkScheduleMask(now, mask)) { + if(checkScheduleMask(now, msk)) { /* We can assume now that the schedule is always repeating with fixed delta */ - unsigned int delta = getScheduleDelta(mask); - if ( ( (std::max(now , start) - std::min(now , start)) % delta ) <= duration ) { + unsigned int delta = getScheduleDelta(msk); + if ( ( (std::max(now , frm) - std::min(now , frm)) % delta ) <= len ) { return true; } } @@ -54,87 +54,87 @@ class Schedule : public TimeService { } Schedule& operator=(Schedule & aSchedule) { - start = aSchedule.start; - end = aSchedule.end; - duration = aSchedule.duration; - mask = aSchedule.mask; + frm = aSchedule.frm; + to = aSchedule.to; + len = aSchedule.len; + msk = aSchedule.msk; return *this; } bool operator==(Schedule & aSchedule) { - return start == aSchedule.start && end == aSchedule.end && duration == aSchedule.duration && mask == aSchedule.mask; + return frm == aSchedule.frm && to == aSchedule.to && len == aSchedule.len && msk == aSchedule.msk; } bool operator!=(Schedule & aSchedule) { return !(operator==(aSchedule)); } private: - bool isScheduleOneShot(unsigned int mask) { - if((mask & 0x3C000000) == 0x00000000) { + bool isScheduleOneShot(unsigned int msk) { + if((msk & 0x3C000000) == 0x00000000) { return true; } else { return false; } } - bool isScheduleFixed(unsigned int mask) { - if((mask & 0x3C000000) == 0x04000000) { + bool isScheduleFixed(unsigned int msk) { + if((msk & 0x3C000000) == 0x04000000) { return true; } else { return false; } } - bool isScheduleWeekly(unsigned int mask) { - if((mask & 0x3C000000) == 0x08000000) { + bool isScheduleWeekly(unsigned int msk) { + if((msk & 0x3C000000) == 0x08000000) { return true; } else { return false; } } - bool isScheduleMonthly(unsigned int mask) { - if((mask & 0x3C000000) == 0x0C000000) { + bool isScheduleMonthly(unsigned int msk) { + if((msk & 0x3C000000) == 0x0C000000) { return true; } else { return false; } } - bool isScheduleYearly(unsigned int mask) { - if((mask & 0x3C000000) == 0x10000000) { + bool isScheduleYearly(unsigned int msk) { + if((msk & 0x3C000000) == 0x10000000) { return true; } else { return false; } } - bool isScheduleInSeconds(unsigned int mask) { - if((mask & 0xC0000000) == 0x00000000) { + bool isScheduleInSeconds(unsigned int msk) { + if((msk & 0xC0000000) == 0x00000000) { return true; } else { return false; } } - bool isScheduleInMinutes(unsigned int mask) { - if((mask & 0xC0000000) == 0x40000000) { + bool isScheduleInMinutes(unsigned int msk) { + if((msk & 0xC0000000) == 0x40000000) { return true; } else { return false; } } - bool isScheduleInHours(unsigned int mask) { - if((mask & 0xC0000000) == 0x80000000) { + bool isScheduleInHours(unsigned int msk) { + if((msk & 0xC0000000) == 0x80000000) { return true; } else { return false; } } - bool isScheduleInDays(unsigned int mask) { - if((mask & 0xC0000000) == 0xC0000000) { + bool isScheduleInDays(unsigned int msk) { + if((msk & 0xC0000000) == 0xC0000000) { return true; } else { return false; @@ -162,38 +162,38 @@ class Schedule : public TimeService { return ptm->tm_mon; } - unsigned int getScheduleRawMask(unsigned int mask) { - return mask & 0x03FFFFFF; + unsigned int getScheduleRawMask(unsigned int msk) { + return msk & 0x03FFFFFF; } - unsigned int getScheduleWeekMask(unsigned int mask) { - return mask & 0x000000FF; + unsigned int getScheduleWeekMask(unsigned int msk) { + return msk & 0x000000FF; } - unsigned int getScheduleDay(unsigned int mask) { - return mask & 0x000000FF; + unsigned int getScheduleDay(unsigned int msk) { + return msk & 0x000000FF; } - unsigned int getScheduleMonth(unsigned int mask) { - return (mask & 0x0000FF00) >> 8; + unsigned int getScheduleMonth(unsigned int msk) { + return (msk & 0x0000FF00) >> 8; } - bool checkSchedulePeriod(unsigned int now, unsigned int start, unsigned int end) { - if(now >= start && (now < end || end == 0)) { + bool checkSchedulePeriod(unsigned int now, unsigned int frm, unsigned int to) { + if(now >= frm && (now < to || to == 0)) { return true; } else { return false; } } - bool checkScheduleMask(unsigned int now, unsigned int mask) { - if(isScheduleFixed(mask) || isScheduleOneShot(mask)) { + bool checkScheduleMask(unsigned int now, unsigned int msk) { + if(isScheduleFixed(msk) || isScheduleOneShot(msk)) { return true; } - if(isScheduleWeekly(mask)) { + if(isScheduleWeekly(msk)) { unsigned int nowMask = timeToWeekMask(now); - unsigned int scheduleMask = getScheduleWeekMask(mask); + unsigned int scheduleMask = getScheduleWeekMask(msk); if((nowMask & scheduleMask) == 0) { return false; @@ -202,9 +202,9 @@ class Schedule : public TimeService { } } - if(isScheduleMonthly(mask)) { + if(isScheduleMonthly(msk)) { unsigned int nowDay = timeToDay(now); - unsigned int scheduleDay = getScheduleDay(mask); + unsigned int scheduleDay = getScheduleDay(msk); if(nowDay != scheduleDay) { return false; @@ -213,11 +213,11 @@ class Schedule : public TimeService { } } - if(isScheduleYearly(mask)) { + if(isScheduleYearly(msk)) { unsigned int nowDay = timeToDay(now); - unsigned int scheduleDay = getScheduleDay(mask); + unsigned int scheduleDay = getScheduleDay(msk); unsigned int nowMonth = timeToMonth(now); - unsigned int scheduleMonth = getScheduleMonth(mask); + unsigned int scheduleMonth = getScheduleMonth(msk); if((nowDay != scheduleDay) || (nowMonth != scheduleMonth)) { return false; @@ -229,26 +229,26 @@ class Schedule : public TimeService { return false; } - unsigned int getScheduleDelta(unsigned int mask) { - if(isScheduleOneShot(mask)) { + unsigned int getScheduleDelta(unsigned int msk) { + if(isScheduleOneShot(msk)) { return 0xFFFFFFFF; } - if(isScheduleFixed(mask)) { - if(isScheduleInSeconds(mask)) { - return getScheduleRawMask(mask); + if(isScheduleFixed(msk)) { + if(isScheduleInSeconds(msk)) { + return getScheduleRawMask(msk); } - if(isScheduleInMinutes(mask)) { - return 60 * getScheduleRawMask(mask); + if(isScheduleInMinutes(msk)) { + return 60 * getScheduleRawMask(msk); } - if(isScheduleInHours(mask)) { - return 60 * 60 * getScheduleRawMask(mask); + if(isScheduleInHours(msk)) { + return 60 * 60 * getScheduleRawMask(msk); } } - if(isScheduleWeekly(mask) || isScheduleMonthly(mask) || isScheduleYearly(mask)) { + if(isScheduleWeekly(msk) || isScheduleMonthly(msk) || isScheduleYearly(msk)) { return 60 * 60 * 24; } @@ -259,10 +259,10 @@ class Schedule : public TimeService { class CloudSchedule : public Property { private: Schedule _value, - _cloud_value; + _cloud_value; public: CloudSchedule() : _value(0, 0, 0, 0), _cloud_value(0, 0, 0, 0) {} - CloudSchedule(unsigned int start, unsigned int end, unsigned int duration, unsigned int mask) : _value(start, end, duration, mask), _cloud_value(start, end, duration, mask) {} + CloudSchedule(unsigned int frm, unsigned int to, unsigned int len, unsigned int msk) : _value(frm, to, len, msk), _cloud_value(frm, to, len, msk) {} virtual bool isDifferentFromCloud() { @@ -270,10 +270,10 @@ class CloudSchedule : public Property { } CloudSchedule& operator=(Schedule aSchedule) { - _value.start = aSchedule.start; - _value.end = aSchedule.end; - _value.duration = aSchedule.duration; - _value.mask = aSchedule.mask; + _value.frm = aSchedule.frm; + _value.to = aSchedule.to; + _value.len = aSchedule.len; + _value.msk = aSchedule.msk; updateLocalTimestamp(); return *this; } @@ -297,17 +297,17 @@ class CloudSchedule : public Property { _cloud_value = _value; } virtual CborError appendAttributesToCloud() { - CHECK_CBOR(appendAttribute(_value.start)); - CHECK_CBOR(appendAttribute(_value.end)); - CHECK_CBOR(appendAttribute(_value.duration)); - CHECK_CBOR(appendAttribute(_value.mask)); + CHECK_CBOR(appendAttribute(_value.frm)); + CHECK_CBOR(appendAttribute(_value.to)); + CHECK_CBOR(appendAttribute(_value.len)); + CHECK_CBOR(appendAttribute(_value.msk)); return CborNoError; } virtual void setAttributesFromCloud() { - setAttribute(_cloud_value.start); - setAttribute(_cloud_value.end); - setAttribute(_cloud_value.duration); - setAttribute(_cloud_value.mask); + setAttribute(_cloud_value.frm); + setAttribute(_cloud_value.to); + setAttribute(_cloud_value.len); + setAttribute(_cloud_value.msk); } }; From 089a633ce4297729c7e08e246f5aef3929f33506 Mon Sep 17 00:00:00 2001 From: pennam Date: Wed, 3 Nov 2021 16:59:13 +0100 Subject: [PATCH 10/27] CloudSchedule refactor --- src/property/types/CloudSchedule.h | 188 ++++++++++++++++------------- 1 file changed, 104 insertions(+), 84 deletions(-) diff --git a/src/property/types/CloudSchedule.h b/src/property/types/CloudSchedule.h index fc018b15f..2f1effef0 100644 --- a/src/property/types/CloudSchedule.h +++ b/src/property/types/CloudSchedule.h @@ -24,9 +24,46 @@ #include #include "../Property.h" +#include "../../AIoTC_Const.h" #include "utility/time/TimeService.h" #include +/****************************************************************************** + * DEFINE + ******************************************************************************/ +#define SCHEDULE_UNIT_MASK 0xC0000000 +#define SCHEDULE_UNIT_SHIFT 30 + +#define SCHEDULE_TYPE_MASK 0x3C000000 +#define SCHEDULE_TYPE_SHIFT 26 + +#define SCHEDULE_MONTH_MASK 0x0000FF00 +#define SCHEDULE_MONTH_SHIFT 8 + +#define SCHEDULE_REP_MASK 0x03FFFFFF +#define SCHEDULE_WEEK_MASK 0x000000FF +#define SCHEDULE_DAY_MASK 0x000000FF + +#define SCHEDULE_ONE_SHOT 0xFFFFFFFF + +/****************************************************************************** + ENUM + ******************************************************************************/ +enum class ScheduleUnit : int { + Seconds = 0, + Minutes = 1, + Hours = 2, + Days = 3 +}; + +enum class ScheduleType : int { + OneShot = 0, + FixedDelta = 1, + Weekly = 2, + Monthly = 3, + Yearly = 4 +}; + /****************************************************************************** CLASS DECLARATION ******************************************************************************/ @@ -69,116 +106,107 @@ class Schedule : public TimeService { return !(operator==(aSchedule)); } private: + ScheduleUnit getScheduleUnit(unsigned int msk) { + return static_cast((msk & SCHEDULE_UNIT_MASK) >> SCHEDULE_UNIT_SHIFT); + } + + ScheduleType getScheduleType(unsigned int msk) { + return static_cast((msk & SCHEDULE_TYPE_MASK) >> SCHEDULE_TYPE_SHIFT); + } + + unsigned int getScheduleRepetition(unsigned int msk) { + return (msk & SCHEDULE_REP_MASK); + } + + unsigned int getScheduleWeekMask(unsigned int msk) { + return (msk & SCHEDULE_WEEK_MASK); + } + + unsigned int getScheduleDay(unsigned int msk) { + return (msk & SCHEDULE_DAY_MASK); + } + + unsigned int getScheduleMonth(unsigned int msk) { + return ((msk & SCHEDULE_MONTH_MASK) >> SCHEDULE_MONTH_SHIFT); + } + bool isScheduleOneShot(unsigned int msk) { - if((msk & 0x3C000000) == 0x00000000) { - return true; - } else { - return false; - } + return (getScheduleType(msk) == ScheduleType::OneShot) ? true : false ; } bool isScheduleFixed(unsigned int msk) { - if((msk & 0x3C000000) == 0x04000000) { - return true; - } else { - return false; - } + return (getScheduleType(msk) == ScheduleType::FixedDelta) ? true : false ; } bool isScheduleWeekly(unsigned int msk) { - if((msk & 0x3C000000) == 0x08000000) { - return true; - } else { - return false; - } + return (getScheduleType(msk) == ScheduleType::Weekly) ? true : false ; } bool isScheduleMonthly(unsigned int msk) { - if((msk & 0x3C000000) == 0x0C000000) { - return true; - } else { - return false; - } + return (getScheduleType(msk) == ScheduleType::Monthly) ? true : false ; } bool isScheduleYearly(unsigned int msk) { - if((msk & 0x3C000000) == 0x10000000) { - return true; - } else { - return false; - } + return (getScheduleType(msk) == ScheduleType::Yearly) ? true : false ; } bool isScheduleInSeconds(unsigned int msk) { - if((msk & 0xC0000000) == 0x00000000) { - return true; + if(isScheduleFixed(msk)) { + return (getScheduleUnit(msk) == ScheduleUnit::Seconds) ? true : false ; } else { return false; } } bool isScheduleInMinutes(unsigned int msk) { - if((msk & 0xC0000000) == 0x40000000) { - return true; + if(isScheduleFixed(msk)) { + return (getScheduleUnit(msk) == ScheduleUnit::Minutes) ? true : false ; } else { return false; } } bool isScheduleInHours(unsigned int msk) { - if((msk & 0xC0000000) == 0x80000000) { - return true; + if(isScheduleFixed(msk)) { + return (getScheduleUnit(msk) == ScheduleUnit::Hours) ? true : false ; } else { return false; } } bool isScheduleInDays(unsigned int msk) { - if((msk & 0xC0000000) == 0xC0000000) { - return true; + if(isScheduleFixed(msk)) { + return (getScheduleUnit(msk) == ScheduleUnit::Days) ? true : false ; } else { return false; } } - unsigned int timeToWeekMask(time_t rawtime) { + unsigned int getCurrentDayMask(time_t time) { struct tm * ptm; - ptm = gmtime ( &rawtime ); + ptm = gmtime (&time); return 1 << ptm->tm_wday; } - unsigned int timeToDay(time_t rawtime) { + unsigned int getCurrentDay(time_t time) { struct tm * ptm; - ptm = gmtime ( &rawtime ); + ptm = gmtime (&time); return ptm->tm_mday; } - unsigned int timeToMonth(time_t rawtime) { + unsigned int getCurrentMonth(time_t time) { struct tm * ptm; - ptm = gmtime ( &rawtime ); + ptm = gmtime (&time); return ptm->tm_mon; } - unsigned int getScheduleRawMask(unsigned int msk) { - return msk & 0x03FFFFFF; - } - - unsigned int getScheduleWeekMask(unsigned int msk) { - return msk & 0x000000FF; - } - - unsigned int getScheduleDay(unsigned int msk) { - return msk & 0x000000FF; - } - - unsigned int getScheduleMonth(unsigned int msk) { - return (msk & 0x0000FF00) >> 8; - } - bool checkSchedulePeriod(unsigned int now, unsigned int frm, unsigned int to) { + /* Check if current time is inside the schedule period. If 'to' is equal to + * 0 the schedule has no end. + */ if(now >= frm && (now < to || to == 0)) { return true; } else { @@ -189,39 +217,33 @@ class Schedule : public TimeService { bool checkScheduleMask(unsigned int now, unsigned int msk) { if(isScheduleFixed(msk) || isScheduleOneShot(msk)) { return true; - } + } if(isScheduleWeekly(msk)) { - unsigned int nowMask = timeToWeekMask(now); + unsigned int currentDayMask = getCurrentDayMask(now); unsigned int scheduleMask = getScheduleWeekMask(msk); - if((nowMask & scheduleMask) == 0) { - return false; - } else { + if((currentDayMask & scheduleMask) != 0) { return true; } } if(isScheduleMonthly(msk)) { - unsigned int nowDay = timeToDay(now); + unsigned int currentDay = getCurrentDay(now); unsigned int scheduleDay = getScheduleDay(msk); - if(nowDay != scheduleDay) { - return false; - } else { + if(currentDay == scheduleDay) { return true; } } if(isScheduleYearly(msk)) { - unsigned int nowDay = timeToDay(now); + unsigned int currentDay = getCurrentDay(now); unsigned int scheduleDay = getScheduleDay(msk); - unsigned int nowMonth = timeToMonth(now); + unsigned int currentMonth = getCurrentMonth(now); unsigned int scheduleMonth = getScheduleMonth(msk); - if((nowDay != scheduleDay) || (nowMonth != scheduleMonth)) { - return false; - } else { + if((currentDay == scheduleDay) && (currentMonth == scheduleMonth)) { return true; } } @@ -230,29 +252,27 @@ class Schedule : public TimeService { } unsigned int getScheduleDelta(unsigned int msk) { - if(isScheduleOneShot(msk)) { - return 0xFFFFFFFF; + if(isScheduleInSeconds(msk)) { + return SECONDS * getScheduleRepetition(msk); } - - if(isScheduleFixed(msk)) { - if(isScheduleInSeconds(msk)) { - return getScheduleRawMask(msk); - } - if(isScheduleInMinutes(msk)) { - return 60 * getScheduleRawMask(msk); - } + if(isScheduleInMinutes(msk)) { + return MINUTES * getScheduleRepetition(msk); + } - if(isScheduleInHours(msk)) { - return 60 * 60 * getScheduleRawMask(msk); - } + if(isScheduleInHours(msk)) { + return HOURS * getScheduleRepetition(msk); + } + + if(isScheduleInDays(msk)) { + return DAYS * getScheduleRepetition(msk); } if(isScheduleWeekly(msk) || isScheduleMonthly(msk) || isScheduleYearly(msk)) { - return 60 * 60 * 24; + return DAYS; } - return 0; + return SCHEDULE_ONE_SHOT; } }; From 5af2f89e98109f89f8ce237be87dcc822beeeea7 Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 4 Nov 2021 15:29:00 +0100 Subject: [PATCH 11/27] Add encode and decode test --- extras/test/src/test_decode.cpp | 26 ++++++++++++++++++++++++++ extras/test/src/test_encode.cpp | 18 ++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/extras/test/src/test_decode.cpp b/extras/test/src/test_decode.cpp index d67afd440..fab8c18d4 100644 --- a/extras/test/src/test_decode.cpp +++ b/extras/test/src/test_decode.cpp @@ -400,6 +400,32 @@ SCENARIO("Arduino Cloud Properties are decoded", "[ArduinoCloudThing::decode]") /************************************************************************************/ + WHEN("A Schedule property is changed via CBOR message") + { + PropertyContainer property_container; + + CloudSchedule schedule_test = CloudSchedule(0, 0, 0, 0); + addPropertyToContainer(property_container, schedule_test, "test", Permission::ReadWrite); + + /* [{0: "test:frm", 2: 1633305600}, {0: "test:to", 2: 1633651200}, {0: "test:len", 2: 600}, {0: "test:msk", 2: 1140850708}] + = 84 A2 00 68 74 65 73 74 3A 66 72 6D 02 1A 61 5A 44 00 A2 00 67 74 65 73 74 3A 74 6F 02 1A 61 5F 8A 00 A2 00 68 74 65 73 74 3A 6C 65 6E 02 19 02 58 A2 00 68 74 65 73 74 3A 6D 73 6B 02 1A 44 00 00 14 + */ + uint8_t const payload[] = {0x84, 0xA2, 0x00, 0x68, 0x74, 0x65, 0x73, 0x74, 0x3A, 0x66, 0x72, 0x6D, 0x02, 0x1A, 0x61, 0x5A, 0x44, 0x00, 0xA2, 0x00, 0x67, 0x74, 0x65, 0x73, 0x74, 0x3A, 0x74, 0x6F, 0x02, 0x1A, 0x61, 0x5F, 0x8A, 0x00, 0xA2, 0x00, 0x68, 0x74, 0x65, 0x73, 0x74, 0x3A, 0x6C, 0x65, 0x6E, 0x02, 0x19, 0x02, 0x58, 0xA2, 0x00, 0x68, 0x74, 0x65, 0x73, 0x74, 0x3A, 0x6D, 0x73, 0x6B, 0x02, 0x1A, 0x44, 0x00, 0x00, 0x14}; + CBORDecoder::decode(property_container, payload, sizeof(payload) / sizeof(uint8_t)); + + Schedule schedule_compare = Schedule(1633305600, 1633651200, 600, 1140850708); + Schedule value_schedule_test = schedule_test.getValue(); + + bool verify = (value_schedule_test == schedule_compare); + REQUIRE(verify); + REQUIRE(value_schedule_test.frm == schedule_compare.frm); + REQUIRE(value_schedule_test.to == schedule_compare.to); + REQUIRE(value_schedule_test.len == schedule_compare.len); + REQUIRE(value_schedule_test.msk == schedule_compare.msk); + } + + /************************************************************************************/ + WHEN("Multiple properties is changed via CBOR message") { WHEN("Multiple properties of different type are changed via CBOR message") diff --git a/extras/test/src/test_encode.cpp b/extras/test/src/test_encode.cpp index 8a4904fc6..f0667166b 100644 --- a/extras/test/src/test_encode.cpp +++ b/extras/test/src/test_encode.cpp @@ -322,6 +322,24 @@ SCENARIO("Arduino Cloud Properties are encoded", "[ArduinoCloudThing::encode-1]" /************************************************************************************/ + WHEN("A 'Schedule' property is added") + { + PropertyContainer property_container; + cbor::encode(property_container); + + CloudSchedule schedule_test = CloudSchedule(1633305600, 1633651200, 600, 1140850708); + addPropertyToContainer(property_container, schedule_test, "test", Permission::ReadWrite); + + /* [{0: "test:frm", 2: 1633305600}, {0: "test:to", 2: 1633651200}, {0: "test:len", 2: 600}, {0: "test:msk", 2: 1140850708}] + = 9F A2 00 68 74 65 73 74 3A 66 72 6D 02 1A 61 5A 44 00 A2 00 67 74 65 73 74 3A 74 6F 02 1A 61 5F 8A 00 A2 00 68 74 65 73 74 3A 6C 65 6E 02 19 02 58 A2 00 68 74 65 73 74 3A 6D 73 6B 02 1A 44 00 00 14 FF + */ + std::vector const expected = {0x9F, 0xA2, 0x00, 0x68, 0x74, 0x65, 0x73, 0x74, 0x3A, 0x66, 0x72, 0x6D, 0x02, 0x1A, 0x61, 0x5A, 0x44, 0x00, 0xA2, 0x00, 0x67, 0x74, 0x65, 0x73, 0x74, 0x3A, 0x74, 0x6F, 0x02, 0x1A, 0x61, 0x5F, 0x8A, 0x00, 0xA2, 0x00, 0x68, 0x74, 0x65, 0x73, 0x74, 0x3A, 0x6C, 0x65, 0x6E, 0x02, 0x19, 0x02, 0x58, 0xA2, 0x00, 0x68, 0x74, 0x65, 0x73, 0x74, 0x3A, 0x6D, 0x73, 0x6B, 0x02, 0x1A, 0x44, 0x00, 0x00, 0x14, 0xFF }; + std::vector const actual = cbor::encode(property_container); + REQUIRE(actual == expected); + } + + /************************************************************************************/ + WHEN("Multiple properties are added") { PropertyContainer property_container; From e901a85bf50c8e63049353294fca5b4902809731 Mon Sep 17 00:00:00 2001 From: pennam Date: Tue, 9 Nov 2021 11:08:12 +0100 Subject: [PATCH 12/27] Add example sketch for CloudSchedule property --- .../ArduinoIoTCloud-Schedule.ino | 54 +++++++++++++++++++ .../arduino_secrets.h | 34 ++++++++++++ .../thingProperties.h | 35 ++++++++++++ 3 files changed, 123 insertions(+) create mode 100644 examples/ArduinoIoTCloud-Schedule/ArduinoIoTCloud-Schedule.ino create mode 100644 examples/ArduinoIoTCloud-Schedule/arduino_secrets.h create mode 100644 examples/ArduinoIoTCloud-Schedule/thingProperties.h diff --git a/examples/ArduinoIoTCloud-Schedule/ArduinoIoTCloud-Schedule.ino b/examples/ArduinoIoTCloud-Schedule/ArduinoIoTCloud-Schedule.ino new file mode 100644 index 000000000..eccd4c1f1 --- /dev/null +++ b/examples/ArduinoIoTCloud-Schedule/ArduinoIoTCloud-Schedule.ino @@ -0,0 +1,54 @@ +/* + This sketch demonstrates how to use cloud schedule data type. + + This sketch is compatible with: + - MKR 1000 + - MKR WIFI 1010 + - MKR GSM 1400 + - MKR NB 1500 + - MKR WAN 1300/1310 + - Nano 33 IoT + - ESP 8266 +*/ + +#include "arduino_secrets.h" +#include "thingProperties.h" + +#if defined(ESP32) +static int const LED_BUILTIN = 2; +#endif + +void setup() { + /* Initialize serial and wait up to 5 seconds for port to open */ + Serial.begin(9600); + for(unsigned long const serialBeginTime = millis(); !Serial && (millis() - serialBeginTime > 5000); ) { } + + /* Configure LED pin as an output */ + pinMode(LED_BUILTIN, OUTPUT); + + /* This function takes care of connecting your sketch variables to the ArduinoIoTCloud object */ + initProperties(); + + /* Initialize Arduino IoT Cloud library */ + ArduinoCloud.begin(ArduinoIoTPreferredConnection); + + setDebugMessageLevel(DBG_INFO); + ArduinoCloud.printDebugInfo(); + + /* Configure a schedule for LED. This should be done with Arduino create Scheduler widget */ + unsigned int startingFrom = 1635786000; /* From 01/11/2021 17:00 */ + unsigned int untilTo = startingFrom + ( DAYS * 28 ); /* To 29/11/2021 17:00 */ + unsigned int executionPeriod = MINUTES * 6; /* For 6 minutes */ + unsigned int scheduleConfiguration = 134217770; /* On monday wednesday and friday */ + + led = Schedule(startingFrom, untilTo, executionPeriod, scheduleConfiguration); +} + +void loop() { + ArduinoCloud.update(); + + /* Activate LED when schedule is active */ + digitalWrite(LED_BUILTIN, led.isActive()); + +} + diff --git a/examples/ArduinoIoTCloud-Schedule/arduino_secrets.h b/examples/ArduinoIoTCloud-Schedule/arduino_secrets.h new file mode 100644 index 000000000..fc0b0661e --- /dev/null +++ b/examples/ArduinoIoTCloud-Schedule/arduino_secrets.h @@ -0,0 +1,34 @@ +#include + +/* MKR1000, MKR WiFi 1010 */ +#if defined(BOARD_HAS_WIFI) + #define SECRET_SSID "YOUR_WIFI_NETWORK_NAME" + #define SECRET_PASS "YOUR_WIFI_PASSWORD" +#endif + +/* ESP8266 */ +#if defined(BOARD_ESP8266) + #define SECRET_DEVICE_KEY "my-device-password" +#endif + +/* MKR GSM 1400 */ +#if defined(BOARD_HAS_GSM) + #define SECRET_PIN "" + #define SECRET_APN "" + #define SECRET_LOGIN "" + #define SECRET_PASS "" +#endif + +/* MKR WAN 1300/1310 */ +#if defined(BOARD_HAS_LORA) + #define SECRET_APP_EUI "" + #define SECRET_APP_KEY "" +#endif + +/* MKR NB 1500 */ +#if defined(BOARD_HAS_NB) + #define SECRET_PIN "" + #define SECRET_APN "" + #define SECRET_LOGIN "" + #define SECRET_PASS "" +#endif diff --git a/examples/ArduinoIoTCloud-Schedule/thingProperties.h b/examples/ArduinoIoTCloud-Schedule/thingProperties.h new file mode 100644 index 000000000..fd63b76a1 --- /dev/null +++ b/examples/ArduinoIoTCloud-Schedule/thingProperties.h @@ -0,0 +1,35 @@ +#include +#include + +#define THING_ID "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" +#define BOARD_ID "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" + +void onSwitchButtonChange(); + +bool switchButton; +CloudSchedule led; + +void initProperties() { +#if defined(BOARD_ESP8266) + ArduinoCloud.setBoardId(BOARD_ID); + ArduinoCloud.setSecretDeviceKey(SECRET_DEVICE_KEY); +#endif + ArduinoCloud.setThingId(THING_ID); +#if defined(BOARD_HAS_WIFI) || defined(BOARD_HAS_GSM) || defined(BOARD_HAS_NB) + ArduinoCloud.addProperty(switchButton, WRITE, ON_CHANGE); + ArduinoCloud.addProperty(led, READWRITE, ON_CHANGE); +#elif defined(BOARD_HAS_LORA) + ArduinoCloud.addProperty(switchButton, 1, WRITE, ON_CHANGE; + ArduinoCloud.addProperty(led, 2, READWRITE, ON_CHANGE); +#endif +} + +#if defined(BOARD_HAS_WIFI) + WiFiConnectionHandler ArduinoIoTPreferredConnection(SECRET_SSID, SECRET_PASS); +#elif defined(BOARD_HAS_GSM) + GSMConnectionHandler ArduinoIoTPreferredConnection(SECRET_PIN, SECRET_APN, SECRET_LOGIN, SECRET_PASS); +#elif defined(BOARD_HAS_LORA) + LoRaConnectionHandler ArduinoIoTPreferredConnection(SECRET_APP_EUI, SECRET_APP_KEY, _lora_band::EU868, NULL, _lora_class::CLASS_A); +#elif defined(BOARD_HAS_NB) + NBConnectionHandler ArduinoIoTPreferredConnection(SECRET_PIN, SECRET_APN, SECRET_LOGIN, SECRET_PASS); +#endif From e2b952621a50f7437081a67e70624b76c209b8a7 Mon Sep 17 00:00:00 2001 From: pennam Date: Tue, 2 Nov 2021 10:09:46 +0100 Subject: [PATCH 13/27] Add properties and logic to handle timezone and dst changes --- src/ArduinoIoTCloud.h | 6 +++++- src/ArduinoIoTCloudTCP.cpp | 16 +++++++++++++++- src/property/types/CloudSchedule.h | 2 +- src/utility/time/TimeService.cpp | 12 ++++++++++++ src/utility/time/TimeService.h | 8 ++++++++ 5 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/ArduinoIoTCloud.h b/src/ArduinoIoTCloud.h index 7c1f9679c..9aad29ea8 100644 --- a/src/ArduinoIoTCloud.h +++ b/src/ArduinoIoTCloud.h @@ -97,7 +97,9 @@ class ArduinoIoTCloudClass inline ConnectionHandler * getConnection() { return _connection; } - inline unsigned long getInternalTime() { return _time_service.getTime(); } + inline unsigned long getInternalTime() { return _time_service.getTime(); } + inline unsigned long getLocalTime() { return _time_service.getLocalTime(); } + inline void updateInternalTimezoneInfo() { _time_service.setTimeZoneData(_tz_offset, _tz_dst_until); } void addCallback(ArduinoIoTCloudEvent const event, OnCloudEventCallback callback); @@ -146,6 +148,8 @@ class ArduinoIoTCloudClass ConnectionHandler * _connection = nullptr; PropertyContainer _property_container; TimeService _time_service; + int _tz_offset = 0; + unsigned int _tz_dst_until = 0; void execCloudEventCallback(ArduinoIoTCloudEvent const event); diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index 4d4f86b9d..11245ea85 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -64,6 +64,11 @@ extern "C" unsigned long getTime() return ArduinoCloud.getInternalTime(); } +extern "C" void updateTimezoneInfo() +{ + ArduinoCloud.updateInternalTimezoneInfo(); +} + /****************************************************************************** CTOR/DTOR ******************************************************************************/ @@ -243,6 +248,9 @@ int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress, addPropertyReal(_ota_req, "OTA_REQ", Permission::ReadWrite).onSync(CLOUD_WINS); #endif /* OTA_ENABLED */ + addPropertyReal(_tz_offset, "tz_offset", Permission::ReadWrite).onSync(CLOUD_WINS).onUpdate(updateTimezoneInfo); + addPropertyReal(_tz_dst_until, "tz_dst_until", Permission::ReadWrite).onSync(CLOUD_WINS).onUpdate(updateTimezoneInfo); + #if OTA_STORAGE_PORTENTA_QSPI #define BOOTLOADER_ADDR (0x8000000) uint32_t bootloader_data_offset = 0x1F000; @@ -527,7 +535,12 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_Connected() */ sendPropertiesToCloud(); - return State::Connected; + unsigned long const internal_posix_time = _time_service.getTime(); + if(internal_posix_time < _tz_dst_until) { + return State::Connected; + } else { + return State::RequestLastValues; + } } } @@ -555,6 +568,7 @@ void ArduinoIoTCloudTCP::handleMessage(int length) DEBUG_VERBOSE("ArduinoIoTCloudTCP::%s [%d] last values received", __FUNCTION__, millis()); CBORDecoder::decode(_property_container, (uint8_t*)bytes, length, true); sendPropertiesToCloud(); + _time_service.setTimeZoneData(_tz_offset, _tz_dst_until); execCloudEventCallback(ArduinoIoTCloudEvent::SYNC); _last_sync_request_cnt = 0; _last_sync_request_tick = 0; diff --git a/src/property/types/CloudSchedule.h b/src/property/types/CloudSchedule.h index 2f1effef0..b7b696214 100644 --- a/src/property/types/CloudSchedule.h +++ b/src/property/types/CloudSchedule.h @@ -74,7 +74,7 @@ class Schedule : public TimeService { bool isActive() { - unsigned int now = getTime(); + unsigned int now = getLocalTime(); if(checkSchedulePeriod(now, frm, to)) { /* We are in the schedule range */ diff --git a/src/utility/time/TimeService.cpp b/src/utility/time/TimeService.cpp index dcd15f83b..6b80c2b51 100644 --- a/src/utility/time/TimeService.cpp +++ b/src/utility/time/TimeService.cpp @@ -91,6 +91,18 @@ unsigned long TimeService::getTime() #endif } +void TimeService::setTimeZoneData(long offset, unsigned long dst_until) +{ + _timezone_offset = offset; + _timezone_dst_until = dst_until; +} + +unsigned long TimeService::getLocalTime() +{ + unsigned long utc = getTime(); + return utc + _timezone_offset; +} + /************************************************************************************** * PRIVATE MEMBER FUNCTIONS **************************************************************************************/ diff --git a/src/utility/time/TimeService.h b/src/utility/time/TimeService.h index ae8c12f35..73335f0b7 100644 --- a/src/utility/time/TimeService.h +++ b/src/utility/time/TimeService.h @@ -24,6 +24,7 @@ #include + #ifdef ARDUINO_ARCH_SAMD #include #endif @@ -46,6 +47,8 @@ class TimeService void begin (ConnectionHandler * con_hdl); unsigned long getTime(); + unsigned long getLocalTime(); + void setTimeZoneData(long offset, unsigned long valid_until); private: @@ -55,8 +58,13 @@ class TimeService #endif unsigned long getRemoteTime(); + static bool isTimeValid(unsigned long const time); +private: + long _timezone_offset; + unsigned long _timezone_dst_until; + }; #endif /* ARDUINO_IOT_CLOUD_TIME_SERVICE_H_ */ From a52d001a8bd1f01c752168807a2700b6f74eab40 Mon Sep 17 00:00:00 2001 From: pennam Date: Wed, 17 Nov 2021 11:46:43 +0100 Subject: [PATCH 14/27] Add TimeService::getLocalTime() fake to unit tests --- extras/test/CMakeLists.txt | 1 + extras/test/src/util/PropertyTestUtil.cpp | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/extras/test/CMakeLists.txt b/extras/test/CMakeLists.txt index a2b9c749e..b707b5254 100644 --- a/extras/test/CMakeLists.txt +++ b/extras/test/CMakeLists.txt @@ -12,6 +12,7 @@ include_directories(include) include_directories(../../src) include_directories(../../src/cbor) include_directories(../../src/property) +include_directories(../../src/utility/time) include_directories(external/catch/v2.12.1/include) include_directories(external/fakeit/v2.0.5/include) diff --git a/extras/test/src/util/PropertyTestUtil.cpp b/extras/test/src/util/PropertyTestUtil.cpp index 35717a385..0048dd38d 100644 --- a/extras/test/src/util/PropertyTestUtil.cpp +++ b/extras/test/src/util/PropertyTestUtil.cpp @@ -7,6 +7,8 @@ **************************************************************************************/ #include +#include +#include /************************************************************************************** FUNCTION DEFINITION @@ -16,3 +18,8 @@ unsigned long getTime() { return 0; } + +unsigned long TimeService::getLocalTime() +{ + return getTime(); +} From 74cf0b2d080c392a68880824fe5dfbbb1444fb6b Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 12 Nov 2021 10:02:11 +0100 Subject: [PATCH 15/27] Add DEBUG_DEBUG print to keep track of offset and dst_until changes --- src/utility/time/TimeService.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/utility/time/TimeService.cpp b/src/utility/time/TimeService.cpp index 6b80c2b51..07e0f7a69 100644 --- a/src/utility/time/TimeService.cpp +++ b/src/utility/time/TimeService.cpp @@ -93,7 +93,12 @@ unsigned long TimeService::getTime() void TimeService::setTimeZoneData(long offset, unsigned long dst_until) { + if(_timezone_offset != offset) + DEBUG_DEBUG("ArduinoIoTCloudTCP::%s tz_offset: [%d]", __FUNCTION__, offset); _timezone_offset = offset; + + if(_timezone_dst_until != dst_until) + DEBUG_DEBUG("ArduinoIoTCloudTCP::%s tz_dst_unitl: [%ul]", __FUNCTION__, dst_until); _timezone_dst_until = dst_until; } From 394da9a0dc5b6a73aa57f6e0a744e58d598786a2 Mon Sep 17 00:00:00 2001 From: pennam Date: Mon, 15 Nov 2021 13:59:26 +0100 Subject: [PATCH 16/27] Add functions to ease Schedule configuration --- src/property/types/CloudSchedule.h | 87 ++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/src/property/types/CloudSchedule.h b/src/property/types/CloudSchedule.h index b7b696214..2b7058c66 100644 --- a/src/property/types/CloudSchedule.h +++ b/src/property/types/CloudSchedule.h @@ -64,6 +64,44 @@ enum class ScheduleType : int { Yearly = 4 }; +enum class ScheduleMonth : int { + Jan = 0, + Feb = 1, + Mar = 2, + Apr = 3, + May = 4, + Jun = 5, + Jul = 6, + Aug = 7, + Sep = 8, + Oct = 9, + Nov = 10, + Dec = 11 +}; + +enum class ScheduleWeekDay : int { + Sun = 0, + Mon = 1, + Tue = 2, + Wed = 3, + Thu = 4, + Fri = 5, + Sat = 6 +}; + +enum class ScheduleState : int { + Inactive = 0, + Active = 1 +}; + +/****************************************************************************** + * TYPEDEF + ******************************************************************************/ +typedef struct ScheduleWeeklyMask { + ScheduleState& operator[](ScheduleWeekDay i) { return day[static_cast(i)];} + ScheduleState day[7]; +}ScheduleWeeklyMask; + /****************************************************************************** CLASS DECLARATION ******************************************************************************/ @@ -90,6 +128,55 @@ class Schedule : public TimeService { return false; } + static unsigned int createOneShotScheduleConfiguration() { + return 0; + } + + static unsigned int createFixedDeltaScheduleConfiguration(ScheduleUnit unit, unsigned int delta) { + unsigned int temp_unit = static_cast(unit); + unsigned int temp_type = static_cast(ScheduleType::FixedDelta); + unsigned int temp_delta = delta; + + if (temp_delta > SCHEDULE_REP_MASK) { + temp_delta = SCHEDULE_REP_MASK; + } + return (temp_unit << SCHEDULE_UNIT_SHIFT) | (temp_type << SCHEDULE_TYPE_SHIFT) | temp_delta; + } + + static unsigned int createWeeklyScheduleConfiguration(ScheduleWeeklyMask weekMask) { + unsigned int temp_week = 0; + unsigned int temp_type = static_cast(ScheduleType::Weekly); + + for(int i = 0; i<7; i++) { + if(weekMask[static_cast(i)] == ScheduleState::Active) { + temp_week |= 1 << i; + } + } + return (temp_type << SCHEDULE_TYPE_SHIFT) | temp_week; + } + + static unsigned int createMonthlyScheduleConfiguration(int dayOfTheMonth) { + int temp_day = dayOfTheMonth; + unsigned int temp_type = static_cast(ScheduleType::Monthly); + + if(temp_day < 1) { + temp_day = 1; + } + + if(temp_day > 31) { + temp_day = 31; + } + return (temp_type << SCHEDULE_TYPE_SHIFT) | temp_day; + } + + static unsigned int createYearlyScheduleConfiguration(ScheduleMonth month, int dayOfTheMonth) { + int temp_day = createMonthlyScheduleConfiguration(dayOfTheMonth); + int temp_month = static_cast(month); + unsigned int temp_type = static_cast(ScheduleType::Yearly); + + return (temp_type << SCHEDULE_TYPE_SHIFT) | (temp_month << SCHEDULE_MONTH_SHIFT)| temp_day; + } + Schedule& operator=(Schedule & aSchedule) { frm = aSchedule.frm; to = aSchedule.to; From c035af88cf08beb11a39dffbcdfbdde406775ba9 Mon Sep 17 00:00:00 2001 From: pennam Date: Mon, 15 Nov 2021 13:38:18 +0100 Subject: [PATCH 17/27] Add getTimeFromString() function to convert an input string into a Schedule timestamp --- src/utility/time/TimeService.cpp | 60 ++++++++++++++++++++++++++++++++ src/utility/time/TimeService.h | 5 ++- 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/src/utility/time/TimeService.cpp b/src/utility/time/TimeService.cpp index 07e0f7a69..e84efbb6a 100644 --- a/src/utility/time/TimeService.cpp +++ b/src/utility/time/TimeService.cpp @@ -108,6 +108,66 @@ unsigned long TimeService::getLocalTime() return utc + _timezone_offset; } +unsigned long TimeService::getTimeFromString(const String& input) +{ + struct tm t = + { + 0 /* tm_sec */, + 0 /* tm_min */, + 0 /* tm_hour */, + 0 /* tm_mday */, + 0 /* tm_mon */, + 0 /* tm_year */, + 0 /* tm_wday */, + 0 /* tm_yday */, + 0 /* tm_isdst */ + }; + + char s_month[16]; + int month, day, year, hour, min, sec; + static const char month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec"; + static const int expected_length = 20; + static const int expected_parameters = 6; + + if(input == nullptr || input.length() != expected_length) + { + DEBUG_ERROR("ArduinoIoTCloudTCP::%s invalid input length", __FUNCTION__); + return 0; + } + + int scanned_parameters = sscanf(input.c_str(), "%d %s %d %d:%d:%d", &year, s_month, &day, &hour, &min, &sec); + + if(scanned_parameters != expected_parameters) + { + DEBUG_ERROR("ArduinoIoTCloudTCP::%s invalid input parameters number", __FUNCTION__); + return 0; + } + + char * s_month_position = strstr(month_names, s_month); + + if(s_month_position == nullptr || strlen(s_month) != 3) { + DEBUG_ERROR("ArduinoIoTCloudTCP::%s invalid month name, use %s", __FUNCTION__, month_names); + return 0; + } + + month = (s_month_position - month_names) / 3; + + if(month < 0 || month > 11 || day < 1 || day > 31 || year < 1900 || hour < 0 || + hour > 24 || min < 0 || min > 60 || sec < 0 || sec > 60) { + DEBUG_ERROR("ArduinoIoTCloudTCP::%s invalid date values", __FUNCTION__); + return 0; + } + + t.tm_mon = month; + t.tm_mday = day; + t.tm_year = year - 1900; + t.tm_hour = hour; + t.tm_min = min; + t.tm_sec = sec; + t.tm_isdst = -1; + + return mktime(&t); +} /************************************************************************************** * PRIVATE MEMBER FUNCTIONS **************************************************************************************/ diff --git a/src/utility/time/TimeService.h b/src/utility/time/TimeService.h index 73335f0b7..3582dd608 100644 --- a/src/utility/time/TimeService.h +++ b/src/utility/time/TimeService.h @@ -24,7 +24,6 @@ #include - #ifdef ARDUINO_ARCH_SAMD #include #endif @@ -49,6 +48,10 @@ class TimeService unsigned long getTime(); unsigned long getLocalTime(); void setTimeZoneData(long offset, unsigned long valid_until); + /* Helper function to convert an input String into a UNIX timestamp. + * The input String format must be as follow "2021 Nov 01 17:00:00" + */ + static unsigned long getTimeFromString(const String& input); private: From d4cfdd6bdc4619e457a5d13cfdfa3de6eca946d3 Mon Sep 17 00:00:00 2001 From: pennam Date: Mon, 15 Nov 2021 13:39:01 +0100 Subject: [PATCH 18/27] Update example adding all schedules types and using schedule configuration functions --- .../ArduinoIoTCloud-Schedule.ino | 197 +++++++++++++++++- .../thingProperties.h | 17 +- 2 files changed, 200 insertions(+), 14 deletions(-) diff --git a/examples/ArduinoIoTCloud-Schedule/ArduinoIoTCloud-Schedule.ino b/examples/ArduinoIoTCloud-Schedule/ArduinoIoTCloud-Schedule.ino index eccd4c1f1..71be7f0bf 100644 --- a/examples/ArduinoIoTCloud-Schedule/ArduinoIoTCloud-Schedule.ino +++ b/examples/ArduinoIoTCloud-Schedule/ArduinoIoTCloud-Schedule.ino @@ -1,7 +1,7 @@ /* - This sketch demonstrates how to use cloud schedule data type. + This sketch demonstrates how to use the cloud schedule variable type. - This sketch is compatible with: + This sketch is compatible with the following boards: - MKR 1000 - MKR WIFI 1010 - MKR GSM 1400 @@ -19,7 +19,7 @@ static int const LED_BUILTIN = 2; #endif void setup() { - /* Initialize serial and wait up to 5 seconds for port to open */ + /* Initialize the serial port and wait up to 5 seconds for a connection */ Serial.begin(9600); for(unsigned long const serialBeginTime = millis(); !Serial && (millis() - serialBeginTime > 5000); ) { } @@ -35,20 +35,195 @@ void setup() { setDebugMessageLevel(DBG_INFO); ArduinoCloud.printDebugInfo(); - /* Configure a schedule for LED. This should be done with Arduino create Scheduler widget */ - unsigned int startingFrom = 1635786000; /* From 01/11/2021 17:00 */ - unsigned int untilTo = startingFrom + ( DAYS * 28 ); /* To 29/11/2021 17:00 */ - unsigned int executionPeriod = MINUTES * 6; /* For 6 minutes */ - unsigned int scheduleConfiguration = 134217770; /* On monday wednesday and friday */ + /* Setup one shot schedule example */ + setupOneShotSchedule(); - led = Schedule(startingFrom, untilTo, executionPeriod, scheduleConfiguration); + /* Setup per minute schedule example */ + setupMinuteSchedule(); + + /* Setup hourly schedule example */ + setupHourlySchedule(); + + /* Setup daily schedule example */ + setupDailySchedule(); + + /* Setup weekly schedule example */ + setupWeeklySchedule(); + + /* Setup monthly schedule example */ + setupMonthlySchedule(); + + /* Setup yearly schedule example */ + setupYearlySchedule(); +} + + /* Setup a schedule with an active period of 5 minutes that doesn't repeat + * Starting from 2021 11 01 17:00:00 + * Until 2021 11 02 17:00:00 + */ +void setupOneShotSchedule() { + + unsigned int startingFrom = Schedule::getTimeFromString("2021 Nov 01 17:00:00"); + unsigned int until = startingFrom + ( DAYS * 1 ); + unsigned int activePeriod = MINUTES * 5; + + /* Warning: there is no cross check between until and activePeriod */ + unsigned int scheduleConfiguration = Schedule::createOneShotScheduleConfiguration(); + + oneShot = Schedule(startingFrom, until, activePeriod, scheduleConfiguration); +} + + /* Setup a schedule with an active period of 15 seconds that repeats each minute + * Starting from 2021 11 01 17:00:00 + * Until 2021 11 02 17:00:00 + */ +void setupMinuteSchedule() { + + unsigned int startingFrom = Schedule::getTimeFromString("2021 Nov 01 17:00:00"); + unsigned int until = startingFrom + ( DAYS * 1 ); + unsigned int activePeriod = SECONDS * 15; + unsigned int repetitionPeriod = 1; + + /* Warning: there is no cross check between repetitionPeriod and activePeriod */ + unsigned int scheduleConfiguration = Schedule::createFixedDeltaScheduleConfiguration(ScheduleUnit::Minutes, repetitionPeriod); + + minute = Schedule(startingFrom, until, activePeriod, scheduleConfiguration); +} + +/* Setup a schedule with an active period of 20 minutes that repeats each hour + * Starting from 2021 11 01 17:00:00 + * Until 2021 11 15 13:00:00 + */ +void setupHourlySchedule() { + + unsigned int startingFrom = Schedule::getTimeFromString("2021 Nov 01 17:00:00"); + unsigned int until = Schedule::getTimeFromString("2021 Nov 15 13:00:00"); + unsigned int activePeriod = MINUTES * 20; + unsigned int repetitionPeriod = 1; + + /* Warning: there is no cross check between repetitionPeriod and activePeriod */ + unsigned int scheduleConfiguration = Schedule::createFixedDeltaScheduleConfiguration(ScheduleUnit::Hours, repetitionPeriod); + + hourly = Schedule(startingFrom, until, activePeriod, scheduleConfiguration); +} + +/* Setup a schedule with an active period of 2 hours that repeats each day + * Starting from 2021 11 01 17:00:00 + * Until 2021 11 15 13:00:00 + */ +void setupDailySchedule() { + + unsigned int startingFrom = Schedule::getTimeFromString("2021 Nov 01 17:00:00"); + unsigned int until = Schedule::getTimeFromString("2021 Nov 15 13:00:00"); + unsigned int activePeriod = HOURS * 2; + unsigned int repetitionPeriod = 1; + + /* Warning: there is no cross check between repetitionPeriod and activePeriod */ + unsigned int scheduleConfiguration = Schedule::createFixedDeltaScheduleConfiguration(ScheduleUnit::Days, repetitionPeriod); + + daily = Schedule(startingFrom, until, activePeriod, scheduleConfiguration); +} + +/* Setup a schedule with an active period of 3 minutes with a weekly configuration + * Starting from 2021 11 01 17:00:00 + * Until 2021 11 31 17:00:00 + * Weekly configuration + * Sunday -> Inactive + * Monday -> Active + * Tuesday -> Inactive + * Wednesday -> Active + * Thursday -> Inactive + * Friday -> Active + * Saturday -> Inactive + */ +void setupWeeklySchedule() { + unsigned int startingFrom = Schedule::getTimeFromString("2021 Nov 01 17:00:00"); + unsigned int until = startingFrom + ( DAYS * 30 ); + unsigned int executionPeriod = MINUTES * 3; + + ScheduleWeeklyMask WeeklyMask = { + ScheduleState::Inactive, /* Sunday */ + ScheduleState::Active, /* Monday */ + ScheduleState::Inactive, /* Tuesday */ + ScheduleState::Active, /* Wednesday */ + ScheduleState::Inactive, /* Thursday */ + ScheduleState::Active, /* Friday */ + ScheduleState::Inactive, /* Saturday */ + }; + + unsigned int scheduleConfiguration = Schedule::createWeeklyScheduleConfiguration(WeeklyMask); + + weekly = Schedule(startingFrom, until, executionPeriod, scheduleConfiguration); +} + +/* Setup a schedule with an active period of 1 day that repeats each third day of the month + * Starting from 2021 11 01 17:00:00 + * Until 2022 11 15 13:00:00 + */ +void setupMonthlySchedule() { + + unsigned int startingFrom = Schedule::getTimeFromString("2021 Nov 01 17:00:00"); + unsigned int until = Schedule::getTimeFromString("2021 Nov 15 13:00:00"); + unsigned int activePeriod = DAYS * 1; + unsigned int dayOfMonth = 3; + + unsigned int scheduleConfiguration = Schedule::createMonthlyScheduleConfiguration(dayOfMonth); + + monthly = Schedule(startingFrom, until, activePeriod, scheduleConfiguration); +} + + +/* Setup a schedule with an active period of 2 days that repeats each year on November 6th + * Starting from 2021 11 06 17:00:00 + * Until 2041 11 15 13:00:00 + */ +void setupYearlySchedule() { + + unsigned int startingFrom = Schedule::getTimeFromString("2021 Nov 06 17:00:00"); + unsigned int until = Schedule::getTimeFromString("2041 Nov 06 13:00:00"); + unsigned int activePeriod = DAYS * 2; + unsigned int dayOfMonth = 6; + + unsigned int scheduleConfiguration = Schedule::createYearlyScheduleConfiguration(ScheduleMonth::Nov, dayOfMonth); + + yearly = Schedule(startingFrom, until, activePeriod, scheduleConfiguration); } void loop() { ArduinoCloud.update(); - /* Activate LED when schedule is active */ - digitalWrite(LED_BUILTIN, led.isActive()); + /* Print a message when the oneShot schedule is active */ + if(oneShot.isActive()) { + Serial.println("One shot schedule is active"); + } + + /* Print a message when the per minute schedule is active */ + if(minute.isActive()) { + Serial.println("Per minute schedule is active"); + } + + /* Print a message when the hourly schedule is active */ + if(hourly.isActive()) { + Serial.println("Hourly schedule is active"); + } + + /* Print a message when the daily schedule is active */ + if(daily.isActive()) { + Serial.println("Daily schedule is active"); + } + /* Activate LED when the weekly schedule is active */ + digitalWrite(LED_BUILTIN, weekly.isActive()); + + /* Print a message when the monthly schedule is active */ + if(monthly.isActive()) { + Serial.println("Monthly schedule is active"); + } + + /* Print a message when the yearly schedule is active */ + if(yearly.isActive()) { + Serial.println("Yearly schedule is active"); + } + } diff --git a/examples/ArduinoIoTCloud-Schedule/thingProperties.h b/examples/ArduinoIoTCloud-Schedule/thingProperties.h index fd63b76a1..a426978ce 100644 --- a/examples/ArduinoIoTCloud-Schedule/thingProperties.h +++ b/examples/ArduinoIoTCloud-Schedule/thingProperties.h @@ -7,7 +7,13 @@ void onSwitchButtonChange(); bool switchButton; -CloudSchedule led; +CloudSchedule oneShot; +CloudSchedule minute; +CloudSchedule hourly; +CloudSchedule daily; +CloudSchedule weekly; +CloudSchedule monthly; +CloudSchedule yearly; void initProperties() { #if defined(BOARD_ESP8266) @@ -17,10 +23,15 @@ void initProperties() { ArduinoCloud.setThingId(THING_ID); #if defined(BOARD_HAS_WIFI) || defined(BOARD_HAS_GSM) || defined(BOARD_HAS_NB) ArduinoCloud.addProperty(switchButton, WRITE, ON_CHANGE); - ArduinoCloud.addProperty(led, READWRITE, ON_CHANGE); + ArduinoCloud.addProperty(oneShot, READWRITE, ON_CHANGE); + ArduinoCloud.addProperty(minute, READWRITE, ON_CHANGE); + ArduinoCloud.addProperty(hourly, READWRITE, ON_CHANGE); + ArduinoCloud.addProperty(daily, READWRITE, ON_CHANGE); + ArduinoCloud.addProperty(weekly, READWRITE, ON_CHANGE); + ArduinoCloud.addProperty(monthly, READWRITE, ON_CHANGE); + ArduinoCloud.addProperty(yearly, READWRITE, ON_CHANGE); #elif defined(BOARD_HAS_LORA) ArduinoCloud.addProperty(switchButton, 1, WRITE, ON_CHANGE; - ArduinoCloud.addProperty(led, 2, READWRITE, ON_CHANGE); #endif } From 14736a1c06d88338f1df8915745d57918c3d7cf1 Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 25 Nov 2021 08:53:50 +0100 Subject: [PATCH 19/27] Make TimeService instance reusable --- .../ArduinoIoTCloud-Schedule.ino | 23 ++++++++++--------- extras/test/src/util/PropertyTestUtil.cpp | 5 ++++ src/ArduinoIoTCloud.h | 8 +++---- src/ArduinoIoTCloudLPWAN.cpp | 4 ++-- src/ArduinoIoTCloudTCP.cpp | 8 +++---- src/property/types/CloudSchedule.h | 6 +++-- src/utility/time/TimeService.cpp | 5 ++++ src/utility/time/TimeService.h | 2 ++ 8 files changed, 38 insertions(+), 23 deletions(-) diff --git a/examples/ArduinoIoTCloud-Schedule/ArduinoIoTCloud-Schedule.ino b/examples/ArduinoIoTCloud-Schedule/ArduinoIoTCloud-Schedule.ino index 71be7f0bf..a64b94f7a 100644 --- a/examples/ArduinoIoTCloud-Schedule/ArduinoIoTCloud-Schedule.ino +++ b/examples/ArduinoIoTCloud-Schedule/ArduinoIoTCloud-Schedule.ino @@ -63,7 +63,7 @@ void setup() { */ void setupOneShotSchedule() { - unsigned int startingFrom = Schedule::getTimeFromString("2021 Nov 01 17:00:00"); + unsigned int startingFrom = TimeService::getTimeFromString("2021 Nov 01 17:00:00"); unsigned int until = startingFrom + ( DAYS * 1 ); unsigned int activePeriod = MINUTES * 5; @@ -79,7 +79,7 @@ void setupOneShotSchedule() { */ void setupMinuteSchedule() { - unsigned int startingFrom = Schedule::getTimeFromString("2021 Nov 01 17:00:00"); + unsigned int startingFrom = TimeService::getTimeFromString("2021 Nov 01 17:00:00"); unsigned int until = startingFrom + ( DAYS * 1 ); unsigned int activePeriod = SECONDS * 15; unsigned int repetitionPeriod = 1; @@ -96,8 +96,8 @@ void setupMinuteSchedule() { */ void setupHourlySchedule() { - unsigned int startingFrom = Schedule::getTimeFromString("2021 Nov 01 17:00:00"); - unsigned int until = Schedule::getTimeFromString("2021 Nov 15 13:00:00"); + unsigned int startingFrom = TimeService::getTimeFromString("2021 Nov 01 17:00:00"); + unsigned int until = TimeService::getTimeFromString("2021 Nov 15 13:00:00"); unsigned int activePeriod = MINUTES * 20; unsigned int repetitionPeriod = 1; @@ -113,8 +113,8 @@ void setupHourlySchedule() { */ void setupDailySchedule() { - unsigned int startingFrom = Schedule::getTimeFromString("2021 Nov 01 17:00:00"); - unsigned int until = Schedule::getTimeFromString("2021 Nov 15 13:00:00"); + unsigned int startingFrom = TimeService::getTimeFromString("2021 Nov 01 17:00:00"); + unsigned int until = TimeService::getTimeFromString("2021 Nov 15 13:00:00"); unsigned int activePeriod = HOURS * 2; unsigned int repetitionPeriod = 1; @@ -137,7 +137,8 @@ void setupDailySchedule() { * Saturday -> Inactive */ void setupWeeklySchedule() { - unsigned int startingFrom = Schedule::getTimeFromString("2021 Nov 01 17:00:00"); + + unsigned int startingFrom = TimeService::getTimeFromString("2021 Nov 01 17:00:00"); unsigned int until = startingFrom + ( DAYS * 30 ); unsigned int executionPeriod = MINUTES * 3; @@ -162,8 +163,8 @@ void setupWeeklySchedule() { */ void setupMonthlySchedule() { - unsigned int startingFrom = Schedule::getTimeFromString("2021 Nov 01 17:00:00"); - unsigned int until = Schedule::getTimeFromString("2021 Nov 15 13:00:00"); + unsigned int startingFrom = TimeService::getTimeFromString("2021 Nov 01 17:00:00"); + unsigned int until = TimeService::getTimeFromString("2021 Nov 15 13:00:00"); unsigned int activePeriod = DAYS * 1; unsigned int dayOfMonth = 3; @@ -179,8 +180,8 @@ void setupMonthlySchedule() { */ void setupYearlySchedule() { - unsigned int startingFrom = Schedule::getTimeFromString("2021 Nov 06 17:00:00"); - unsigned int until = Schedule::getTimeFromString("2041 Nov 06 13:00:00"); + unsigned int startingFrom = TimeService::getTimeFromString("2021 Nov 06 17:00:00"); + unsigned int until = TimeService::getTimeFromString("2041 Nov 06 13:00:00"); unsigned int activePeriod = DAYS * 2; unsigned int dayOfMonth = 6; diff --git a/extras/test/src/util/PropertyTestUtil.cpp b/extras/test/src/util/PropertyTestUtil.cpp index 0048dd38d..ef6d85a99 100644 --- a/extras/test/src/util/PropertyTestUtil.cpp +++ b/extras/test/src/util/PropertyTestUtil.cpp @@ -23,3 +23,8 @@ unsigned long TimeService::getLocalTime() { return getTime(); } + +TimeService* ArduinoIoTCloudTimeService() { + static TimeService _timeService_instance; + return &_timeService_instance; +} diff --git a/src/ArduinoIoTCloud.h b/src/ArduinoIoTCloud.h index 9aad29ea8..5041bc359 100644 --- a/src/ArduinoIoTCloud.h +++ b/src/ArduinoIoTCloud.h @@ -97,9 +97,9 @@ class ArduinoIoTCloudClass inline ConnectionHandler * getConnection() { return _connection; } - inline unsigned long getInternalTime() { return _time_service.getTime(); } - inline unsigned long getLocalTime() { return _time_service.getLocalTime(); } - inline void updateInternalTimezoneInfo() { _time_service.setTimeZoneData(_tz_offset, _tz_dst_until); } + inline unsigned long getInternalTime() { return _time_service->getTime(); } + inline unsigned long getLocalTime() { return _time_service->getLocalTime(); } + inline void updateInternalTimezoneInfo() { _time_service->setTimeZoneData(_tz_offset, _tz_dst_until); } void addCallback(ArduinoIoTCloudEvent const event, OnCloudEventCallback callback); @@ -147,7 +147,7 @@ class ArduinoIoTCloudClass ConnectionHandler * _connection = nullptr; PropertyContainer _property_container; - TimeService _time_service; + TimeService * _time_service = ArduinoIoTCloudTimeService(); int _tz_offset = 0; unsigned int _tz_dst_until = 0; diff --git a/src/ArduinoIoTCloudLPWAN.cpp b/src/ArduinoIoTCloudLPWAN.cpp index 29458f21a..17da1f651 100644 --- a/src/ArduinoIoTCloudLPWAN.cpp +++ b/src/ArduinoIoTCloudLPWAN.cpp @@ -68,7 +68,7 @@ int ArduinoIoTCloudLPWAN::begin(ConnectionHandler& connection, bool retry) { _connection = &connection; _retryEnable = retry; - _time_service.begin(nullptr); + _time_service->begin(nullptr); return 1; } @@ -105,7 +105,7 @@ ArduinoIoTCloudLPWAN::State ArduinoIoTCloudLPWAN::handle_ConnectPhy() ArduinoIoTCloudLPWAN::State ArduinoIoTCloudLPWAN::handle_SyncTime() { - unsigned long const internal_posix_time = _time_service.getTime(); + unsigned long const internal_posix_time = _time_service->getTime(); DEBUG_VERBOSE("ArduinoIoTCloudLPWAN::%s internal clock configured to posix timestamp %d", __FUNCTION__, internal_posix_time); DEBUG_INFO("Connected to Arduino IoT Cloud"); return State::Connected; diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index 11245ea85..c4e469e53 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -115,7 +115,7 @@ int ArduinoIoTCloudTCP::begin(ConnectionHandler & connection, bool const enable_ _connection = &connection; _brokerAddress = brokerAddress; _brokerPort = brokerPort; - _time_service.begin(&connection); + _time_service->begin(&connection); return begin(enable_watchdog, _brokerAddress, _brokerPort); } @@ -371,7 +371,7 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_ConnectPhy() ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SyncTime() { - unsigned long const internal_posix_time = _time_service.getTime(); + unsigned long const internal_posix_time = _time_service->getTime(); DEBUG_VERBOSE("ArduinoIoTCloudTCP::%s internal clock configured to posix timestamp %d", __FUNCTION__, internal_posix_time); return State::ConnectMqttBroker; } @@ -535,7 +535,7 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_Connected() */ sendPropertiesToCloud(); - unsigned long const internal_posix_time = _time_service.getTime(); + unsigned long const internal_posix_time = _time_service->getTime(); if(internal_posix_time < _tz_dst_until) { return State::Connected; } else { @@ -568,7 +568,7 @@ void ArduinoIoTCloudTCP::handleMessage(int length) DEBUG_VERBOSE("ArduinoIoTCloudTCP::%s [%d] last values received", __FUNCTION__, millis()); CBORDecoder::decode(_property_container, (uint8_t*)bytes, length, true); sendPropertiesToCloud(); - _time_service.setTimeZoneData(_tz_offset, _tz_dst_until); + _time_service->setTimeZoneData(_tz_offset, _tz_dst_until); execCloudEventCallback(ArduinoIoTCloudEvent::SYNC); _last_sync_request_cnt = 0; _last_sync_request_tick = 0; diff --git a/src/property/types/CloudSchedule.h b/src/property/types/CloudSchedule.h index 2b7058c66..ba898fedf 100644 --- a/src/property/types/CloudSchedule.h +++ b/src/property/types/CloudSchedule.h @@ -105,14 +105,14 @@ typedef struct ScheduleWeeklyMask { /****************************************************************************** CLASS DECLARATION ******************************************************************************/ -class Schedule : public TimeService { +class Schedule { public: unsigned int frm, to, len, msk; Schedule(unsigned int s, unsigned int e, unsigned int d, unsigned int m): frm(s), to(e), len(d), msk(m) {} bool isActive() { - unsigned int now = getLocalTime(); + unsigned int now = _schedule_time_service->getLocalTime(); if(checkSchedulePeriod(now, frm, to)) { /* We are in the schedule range */ @@ -193,6 +193,8 @@ class Schedule : public TimeService { return !(operator==(aSchedule)); } private: + TimeService * _schedule_time_service = ArduinoIoTCloudTimeService(); + ScheduleUnit getScheduleUnit(unsigned int msk) { return static_cast((msk & SCHEDULE_UNIT_MASK) >> SCHEDULE_UNIT_SHIFT); } diff --git a/src/utility/time/TimeService.cpp b/src/utility/time/TimeService.cpp index e84efbb6a..e919b2ea6 100644 --- a/src/utility/time/TimeService.cpp +++ b/src/utility/time/TimeService.cpp @@ -247,3 +247,8 @@ time_t cvt_time(char const * time) return mktime(&t); } + +TimeService* ArduinoIoTCloudTimeService() { + static TimeService _timeService_instance; + return &_timeService_instance; +} diff --git a/src/utility/time/TimeService.h b/src/utility/time/TimeService.h index 3582dd608..4de6c222c 100644 --- a/src/utility/time/TimeService.h +++ b/src/utility/time/TimeService.h @@ -70,4 +70,6 @@ class TimeService }; +TimeService* ArduinoIoTCloudTimeService(); + #endif /* ARDUINO_IOT_CLOUD_TIME_SERVICE_H_ */ From 4bbe08716e1f1eebefbae1a067e76b4911989f38 Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 25 Nov 2021 10:34:05 +0100 Subject: [PATCH 20/27] Add check for valid time --- src/property/types/CloudSchedule.h | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/property/types/CloudSchedule.h b/src/property/types/CloudSchedule.h index ba898fedf..9de6f62c9 100644 --- a/src/property/types/CloudSchedule.h +++ b/src/property/types/CloudSchedule.h @@ -113,15 +113,20 @@ class Schedule { bool isActive() { unsigned int now = _schedule_time_service->getLocalTime(); - if(checkSchedulePeriod(now, frm, to)) { - /* We are in the schedule range */ - if(checkScheduleMask(now, msk)) { + if(checkTimeValid(now)) { + /* We have to wait RTC configuration and Timezone setting from the cloud */ + + if(checkSchedulePeriod(now, frm, to)) { + /* We are in the schedule range */ + + if(checkScheduleMask(now, msk)) { - /* We can assume now that the schedule is always repeating with fixed delta */ - unsigned int delta = getScheduleDelta(msk); - if ( ( (std::max(now , frm) - std::min(now , frm)) % delta ) <= len ) { - return true; + /* We can assume now that the schedule is always repeating with fixed delta */ + unsigned int delta = getScheduleDelta(msk); + if ( ( (std::max(now , frm) - std::min(now , frm)) % delta ) <= len ) { + return true; + } } } } @@ -292,6 +297,10 @@ class Schedule { return ptm->tm_mon; } + bool checkTimeValid(unsigned int now) { + return (now != 0); + } + bool checkSchedulePeriod(unsigned int now, unsigned int frm, unsigned int to) { /* Check if current time is inside the schedule period. If 'to' is equal to * 0 the schedule has no end. From d5a676adf5cd9b8672687cb5a5a0a02c58d96836 Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 25 Nov 2021 10:37:59 +0100 Subject: [PATCH 21/27] Return a valid localtime only if timezone is configured and initialize private varibles in constructor --- src/utility/time/TimeService.cpp | 12 +++++++++++- src/utility/time/TimeService.h | 8 +++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/utility/time/TimeService.cpp b/src/utility/time/TimeService.cpp index e919b2ea6..18b53e297 100644 --- a/src/utility/time/TimeService.cpp +++ b/src/utility/time/TimeService.cpp @@ -44,6 +44,7 @@ time_t cvt_time(char const * time); **************************************************************************************/ static time_t const EPOCH_AT_COMPILE_TIME = cvt_time(__DATE__); +static time_t const EPOCH = 0; /************************************************************************************** * CTOR/DTOR @@ -54,6 +55,9 @@ TimeService::TimeService() #if defined (ARDUINO_ARCH_SAMD) || defined (ARDUINO_ARCH_MBED) , _is_rtc_configured(false) #endif +, _is_tz_configured(false) +, _timezone_offset(0) +, _timezone_dst_until(0) { } @@ -100,12 +104,18 @@ void TimeService::setTimeZoneData(long offset, unsigned long dst_until) if(_timezone_dst_until != dst_until) DEBUG_DEBUG("ArduinoIoTCloudTCP::%s tz_dst_unitl: [%ul]", __FUNCTION__, dst_until); _timezone_dst_until = dst_until; + + _is_tz_configured = true; } unsigned long TimeService::getLocalTime() { unsigned long utc = getTime(); - return utc + _timezone_offset; + if(_is_tz_configured) { + return utc + _timezone_offset; + } else { + return EPOCH; + } } unsigned long TimeService::getTimeFromString(const String& input) diff --git a/src/utility/time/TimeService.h b/src/utility/time/TimeService.h index 4de6c222c..88b3ca986 100644 --- a/src/utility/time/TimeService.h +++ b/src/utility/time/TimeService.h @@ -59,15 +59,13 @@ class TimeService #if defined (ARDUINO_ARCH_SAMD) || defined (ARDUINO_ARCH_MBED) bool _is_rtc_configured; #endif + bool _is_tz_configured; + long _timezone_offset; + unsigned long _timezone_dst_until; unsigned long getRemoteTime(); - static bool isTimeValid(unsigned long const time); -private: - long _timezone_offset; - unsigned long _timezone_dst_until; - }; TimeService* ArduinoIoTCloudTimeService(); From cb39907dd2db0ce107a7ede8470c09aabfb8c74d Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 25 Nov 2021 12:22:36 +0100 Subject: [PATCH 22/27] Do not store EPOCH_AT_COMPILE_TIME into the RTC --- src/utility/time/TimeService.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/utility/time/TimeService.cpp b/src/utility/time/TimeService.cpp index 18b53e297..83b9bc4e9 100644 --- a/src/utility/time/TimeService.cpp +++ b/src/utility/time/TimeService.cpp @@ -79,15 +79,25 @@ unsigned long TimeService::getTime() #ifdef ARDUINO_ARCH_SAMD if(!_is_rtc_configured) { - rtc.setEpoch(getRemoteTime()); - _is_rtc_configured = true; + unsigned long utc = getRemoteTime(); + if(EPOCH_AT_COMPILE_TIME != utc) + { + rtc.setEpoch(utc); + _is_rtc_configured = true; + } + return utc; } return rtc.getEpoch(); #elif ARDUINO_ARCH_MBED if(!_is_rtc_configured) { - set_time(getRemoteTime()); - _is_rtc_configured = true; + unsigned long utc = getRemoteTime(); + if(EPOCH_AT_COMPILE_TIME != utc) + { + set_time(utc); + _is_rtc_configured = true; + } + return utc; } return time(NULL); #else From 0776f4b8baef9e450dc0d9f91ff7930e05b0587d Mon Sep 17 00:00:00 2001 From: pennam Date: Mon, 29 Nov 2021 16:36:46 +0100 Subject: [PATCH 23/27] Use correct destination type when casting enums --- src/property/types/CloudSchedule.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/property/types/CloudSchedule.h b/src/property/types/CloudSchedule.h index 9de6f62c9..5d0b09dbe 100644 --- a/src/property/types/CloudSchedule.h +++ b/src/property/types/CloudSchedule.h @@ -138,8 +138,8 @@ class Schedule { } static unsigned int createFixedDeltaScheduleConfiguration(ScheduleUnit unit, unsigned int delta) { - unsigned int temp_unit = static_cast(unit); - unsigned int temp_type = static_cast(ScheduleType::FixedDelta); + int temp_unit = static_cast(unit); + int temp_type = static_cast(ScheduleType::FixedDelta); unsigned int temp_delta = delta; if (temp_delta > SCHEDULE_REP_MASK) { @@ -150,7 +150,7 @@ class Schedule { static unsigned int createWeeklyScheduleConfiguration(ScheduleWeeklyMask weekMask) { unsigned int temp_week = 0; - unsigned int temp_type = static_cast(ScheduleType::Weekly); + int temp_type = static_cast(ScheduleType::Weekly); for(int i = 0; i<7; i++) { if(weekMask[static_cast(i)] == ScheduleState::Active) { @@ -162,7 +162,7 @@ class Schedule { static unsigned int createMonthlyScheduleConfiguration(int dayOfTheMonth) { int temp_day = dayOfTheMonth; - unsigned int temp_type = static_cast(ScheduleType::Monthly); + int temp_type = static_cast(ScheduleType::Monthly); if(temp_day < 1) { temp_day = 1; @@ -175,9 +175,9 @@ class Schedule { } static unsigned int createYearlyScheduleConfiguration(ScheduleMonth month, int dayOfTheMonth) { - int temp_day = createMonthlyScheduleConfiguration(dayOfTheMonth); + unsigned int temp_day = createMonthlyScheduleConfiguration(dayOfTheMonth); int temp_month = static_cast(month); - unsigned int temp_type = static_cast(ScheduleType::Yearly); + int temp_type = static_cast(ScheduleType::Yearly); return (temp_type << SCHEDULE_TYPE_SHIFT) | (temp_month << SCHEDULE_MONTH_SHIFT)| temp_day; } From 028c2998f372282c900cbd20c8244fe9a0b3e49b Mon Sep 17 00:00:00 2001 From: pennam Date: Mon, 29 Nov 2021 16:30:30 +0100 Subject: [PATCH 24/27] Use ScheduleTimeType and ScheduleConfigurationType instead of unsigned int --- .../ArduinoIoTCloud-Schedule.ino | 54 ++++++++-------- src/property/types/CloudSchedule.h | 61 ++++++++++--------- 2 files changed, 59 insertions(+), 56 deletions(-) diff --git a/examples/ArduinoIoTCloud-Schedule/ArduinoIoTCloud-Schedule.ino b/examples/ArduinoIoTCloud-Schedule/ArduinoIoTCloud-Schedule.ino index a64b94f7a..c035079e4 100644 --- a/examples/ArduinoIoTCloud-Schedule/ArduinoIoTCloud-Schedule.ino +++ b/examples/ArduinoIoTCloud-Schedule/ArduinoIoTCloud-Schedule.ino @@ -63,12 +63,12 @@ void setup() { */ void setupOneShotSchedule() { - unsigned int startingFrom = TimeService::getTimeFromString("2021 Nov 01 17:00:00"); - unsigned int until = startingFrom + ( DAYS * 1 ); - unsigned int activePeriod = MINUTES * 5; + ScheduleTimeType startingFrom = TimeService::getTimeFromString("2021 Nov 01 17:00:00"); + ScheduleTimeType until = startingFrom + ( DAYS * 1 ); + ScheduleTimeType activePeriod = MINUTES * 5; /* Warning: there is no cross check between until and activePeriod */ - unsigned int scheduleConfiguration = Schedule::createOneShotScheduleConfiguration(); + ScheduleConfigurationType scheduleConfiguration = Schedule::createOneShotScheduleConfiguration(); oneShot = Schedule(startingFrom, until, activePeriod, scheduleConfiguration); } @@ -79,13 +79,13 @@ void setupOneShotSchedule() { */ void setupMinuteSchedule() { - unsigned int startingFrom = TimeService::getTimeFromString("2021 Nov 01 17:00:00"); - unsigned int until = startingFrom + ( DAYS * 1 ); - unsigned int activePeriod = SECONDS * 15; + ScheduleTimeType startingFrom = TimeService::getTimeFromString("2021 Nov 01 17:00:00"); + ScheduleTimeType until = startingFrom + ( DAYS * 1 ); + ScheduleTimeType activePeriod = SECONDS * 15; unsigned int repetitionPeriod = 1; /* Warning: there is no cross check between repetitionPeriod and activePeriod */ - unsigned int scheduleConfiguration = Schedule::createFixedDeltaScheduleConfiguration(ScheduleUnit::Minutes, repetitionPeriod); + ScheduleConfigurationType scheduleConfiguration = Schedule::createFixedDeltaScheduleConfiguration(ScheduleUnit::Minutes, repetitionPeriod); minute = Schedule(startingFrom, until, activePeriod, scheduleConfiguration); } @@ -96,13 +96,13 @@ void setupMinuteSchedule() { */ void setupHourlySchedule() { - unsigned int startingFrom = TimeService::getTimeFromString("2021 Nov 01 17:00:00"); - unsigned int until = TimeService::getTimeFromString("2021 Nov 15 13:00:00"); - unsigned int activePeriod = MINUTES * 20; + ScheduleTimeType startingFrom = TimeService::getTimeFromString("2021 Nov 01 17:00:00"); + ScheduleTimeType until = TimeService::getTimeFromString("2021 Nov 15 13:00:00"); + ScheduleTimeType activePeriod = MINUTES * 20; unsigned int repetitionPeriod = 1; /* Warning: there is no cross check between repetitionPeriod and activePeriod */ - unsigned int scheduleConfiguration = Schedule::createFixedDeltaScheduleConfiguration(ScheduleUnit::Hours, repetitionPeriod); + ScheduleConfigurationType scheduleConfiguration = Schedule::createFixedDeltaScheduleConfiguration(ScheduleUnit::Hours, repetitionPeriod); hourly = Schedule(startingFrom, until, activePeriod, scheduleConfiguration); } @@ -113,13 +113,13 @@ void setupHourlySchedule() { */ void setupDailySchedule() { - unsigned int startingFrom = TimeService::getTimeFromString("2021 Nov 01 17:00:00"); - unsigned int until = TimeService::getTimeFromString("2021 Nov 15 13:00:00"); - unsigned int activePeriod = HOURS * 2; + ScheduleTimeType startingFrom = TimeService::getTimeFromString("2021 Nov 01 17:00:00"); + ScheduleTimeType until = TimeService::getTimeFromString("2021 Nov 15 13:00:00"); + ScheduleTimeType activePeriod = HOURS * 2; unsigned int repetitionPeriod = 1; /* Warning: there is no cross check between repetitionPeriod and activePeriod */ - unsigned int scheduleConfiguration = Schedule::createFixedDeltaScheduleConfiguration(ScheduleUnit::Days, repetitionPeriod); + ScheduleConfigurationType scheduleConfiguration = Schedule::createFixedDeltaScheduleConfiguration(ScheduleUnit::Days, repetitionPeriod); daily = Schedule(startingFrom, until, activePeriod, scheduleConfiguration); } @@ -152,7 +152,7 @@ void setupWeeklySchedule() { ScheduleState::Inactive, /* Saturday */ }; - unsigned int scheduleConfiguration = Schedule::createWeeklyScheduleConfiguration(WeeklyMask); + ScheduleConfigurationType scheduleConfiguration = Schedule::createWeeklyScheduleConfiguration(WeeklyMask); weekly = Schedule(startingFrom, until, executionPeriod, scheduleConfiguration); } @@ -163,12 +163,12 @@ void setupWeeklySchedule() { */ void setupMonthlySchedule() { - unsigned int startingFrom = TimeService::getTimeFromString("2021 Nov 01 17:00:00"); - unsigned int until = TimeService::getTimeFromString("2021 Nov 15 13:00:00"); - unsigned int activePeriod = DAYS * 1; - unsigned int dayOfMonth = 3; + ScheduleTimeType startingFrom = TimeService::getTimeFromString("2021 Nov 01 17:00:00"); + ScheduleTimeType until = TimeService::getTimeFromString("2021 Nov 15 13:00:00"); + ScheduleTimeType activePeriod = DAYS * 1; + int dayOfMonth = 3; - unsigned int scheduleConfiguration = Schedule::createMonthlyScheduleConfiguration(dayOfMonth); + ScheduleConfigurationType scheduleConfiguration = Schedule::createMonthlyScheduleConfiguration(dayOfMonth); monthly = Schedule(startingFrom, until, activePeriod, scheduleConfiguration); } @@ -180,12 +180,12 @@ void setupMonthlySchedule() { */ void setupYearlySchedule() { - unsigned int startingFrom = TimeService::getTimeFromString("2021 Nov 06 17:00:00"); - unsigned int until = TimeService::getTimeFromString("2041 Nov 06 13:00:00"); - unsigned int activePeriod = DAYS * 2; - unsigned int dayOfMonth = 6; + ScheduleTimeType startingFrom = TimeService::getTimeFromString("2021 Nov 06 17:00:00"); + ScheduleTimeType until = TimeService::getTimeFromString("2041 Nov 06 13:00:00"); + ScheduleTimeType activePeriod = DAYS * 2; + int dayOfMonth = 6; - unsigned int scheduleConfiguration = Schedule::createYearlyScheduleConfiguration(ScheduleMonth::Nov, dayOfMonth); + ScheduleConfigurationType scheduleConfiguration = Schedule::createYearlyScheduleConfiguration(ScheduleMonth::Nov, dayOfMonth); yearly = Schedule(startingFrom, until, activePeriod, scheduleConfiguration); } diff --git a/src/property/types/CloudSchedule.h b/src/property/types/CloudSchedule.h index 5d0b09dbe..0dcdf4cf6 100644 --- a/src/property/types/CloudSchedule.h +++ b/src/property/types/CloudSchedule.h @@ -102,17 +102,20 @@ typedef struct ScheduleWeeklyMask { ScheduleState day[7]; }ScheduleWeeklyMask; +typedef unsigned int ScheduleTimeType; +typedef unsigned int ScheduleConfigurationType; + /****************************************************************************** CLASS DECLARATION ******************************************************************************/ class Schedule { public: - unsigned int frm, to, len, msk; - Schedule(unsigned int s, unsigned int e, unsigned int d, unsigned int m): frm(s), to(e), len(d), msk(m) {} + ScheduleTimeType frm, to, len, msk; + Schedule(ScheduleTimeType s, ScheduleTimeType e, ScheduleTimeType d, ScheduleConfigurationType m): frm(s), to(e), len(d), msk(m) {} bool isActive() { - unsigned int now = _schedule_time_service->getLocalTime(); + ScheduleTimeType now = _schedule_time_service->getLocalTime(); if(checkTimeValid(now)) { /* We have to wait RTC configuration and Timezone setting from the cloud */ @@ -121,9 +124,9 @@ class Schedule { /* We are in the schedule range */ if(checkScheduleMask(now, msk)) { - + /* We can assume now that the schedule is always repeating with fixed delta */ - unsigned int delta = getScheduleDelta(msk); + ScheduleTimeType delta = getScheduleDelta(msk); if ( ( (std::max(now , frm) - std::min(now , frm)) % delta ) <= len ) { return true; } @@ -133,11 +136,11 @@ class Schedule { return false; } - static unsigned int createOneShotScheduleConfiguration() { + static ScheduleConfigurationType createOneShotScheduleConfiguration() { return 0; } - static unsigned int createFixedDeltaScheduleConfiguration(ScheduleUnit unit, unsigned int delta) { + static ScheduleConfigurationType createFixedDeltaScheduleConfiguration(ScheduleUnit unit, unsigned int delta) { int temp_unit = static_cast(unit); int temp_type = static_cast(ScheduleType::FixedDelta); unsigned int temp_delta = delta; @@ -148,7 +151,7 @@ class Schedule { return (temp_unit << SCHEDULE_UNIT_SHIFT) | (temp_type << SCHEDULE_TYPE_SHIFT) | temp_delta; } - static unsigned int createWeeklyScheduleConfiguration(ScheduleWeeklyMask weekMask) { + static ScheduleConfigurationType createWeeklyScheduleConfiguration(ScheduleWeeklyMask weekMask) { unsigned int temp_week = 0; int temp_type = static_cast(ScheduleType::Weekly); @@ -160,7 +163,7 @@ class Schedule { return (temp_type << SCHEDULE_TYPE_SHIFT) | temp_week; } - static unsigned int createMonthlyScheduleConfiguration(int dayOfTheMonth) { + static ScheduleConfigurationType createMonthlyScheduleConfiguration(int dayOfTheMonth) { int temp_day = dayOfTheMonth; int temp_type = static_cast(ScheduleType::Monthly); @@ -174,7 +177,7 @@ class Schedule { return (temp_type << SCHEDULE_TYPE_SHIFT) | temp_day; } - static unsigned int createYearlyScheduleConfiguration(ScheduleMonth month, int dayOfTheMonth) { + static ScheduleConfigurationType createYearlyScheduleConfiguration(ScheduleMonth month, int dayOfTheMonth) { unsigned int temp_day = createMonthlyScheduleConfiguration(dayOfTheMonth); int temp_month = static_cast(month); int temp_type = static_cast(ScheduleType::Yearly); @@ -200,51 +203,51 @@ class Schedule { private: TimeService * _schedule_time_service = ArduinoIoTCloudTimeService(); - ScheduleUnit getScheduleUnit(unsigned int msk) { + ScheduleUnit getScheduleUnit(ScheduleConfigurationType msk) { return static_cast((msk & SCHEDULE_UNIT_MASK) >> SCHEDULE_UNIT_SHIFT); } - ScheduleType getScheduleType(unsigned int msk) { + ScheduleType getScheduleType(ScheduleConfigurationType msk) { return static_cast((msk & SCHEDULE_TYPE_MASK) >> SCHEDULE_TYPE_SHIFT); } - unsigned int getScheduleRepetition(unsigned int msk) { + unsigned int getScheduleRepetition(ScheduleConfigurationType msk) { return (msk & SCHEDULE_REP_MASK); } - unsigned int getScheduleWeekMask(unsigned int msk) { + unsigned int getScheduleWeekMask(ScheduleConfigurationType msk) { return (msk & SCHEDULE_WEEK_MASK); } - unsigned int getScheduleDay(unsigned int msk) { + unsigned int getScheduleDay(ScheduleConfigurationType msk) { return (msk & SCHEDULE_DAY_MASK); } - unsigned int getScheduleMonth(unsigned int msk) { + unsigned int getScheduleMonth(ScheduleConfigurationType msk) { return ((msk & SCHEDULE_MONTH_MASK) >> SCHEDULE_MONTH_SHIFT); } - bool isScheduleOneShot(unsigned int msk) { + bool isScheduleOneShot(ScheduleConfigurationType msk) { return (getScheduleType(msk) == ScheduleType::OneShot) ? true : false ; } - bool isScheduleFixed(unsigned int msk) { + bool isScheduleFixed(ScheduleConfigurationType msk) { return (getScheduleType(msk) == ScheduleType::FixedDelta) ? true : false ; } - bool isScheduleWeekly(unsigned int msk) { + bool isScheduleWeekly(ScheduleConfigurationType msk) { return (getScheduleType(msk) == ScheduleType::Weekly) ? true : false ; } - bool isScheduleMonthly(unsigned int msk) { + bool isScheduleMonthly(ScheduleConfigurationType msk) { return (getScheduleType(msk) == ScheduleType::Monthly) ? true : false ; } - bool isScheduleYearly(unsigned int msk) { + bool isScheduleYearly(ScheduleConfigurationType msk) { return (getScheduleType(msk) == ScheduleType::Yearly) ? true : false ; } - bool isScheduleInSeconds(unsigned int msk) { + bool isScheduleInSeconds(ScheduleConfigurationType msk) { if(isScheduleFixed(msk)) { return (getScheduleUnit(msk) == ScheduleUnit::Seconds) ? true : false ; } else { @@ -252,7 +255,7 @@ class Schedule { } } - bool isScheduleInMinutes(unsigned int msk) { + bool isScheduleInMinutes(ScheduleConfigurationType msk) { if(isScheduleFixed(msk)) { return (getScheduleUnit(msk) == ScheduleUnit::Minutes) ? true : false ; } else { @@ -260,7 +263,7 @@ class Schedule { } } - bool isScheduleInHours(unsigned int msk) { + bool isScheduleInHours(ScheduleConfigurationType msk) { if(isScheduleFixed(msk)) { return (getScheduleUnit(msk) == ScheduleUnit::Hours) ? true : false ; } else { @@ -268,7 +271,7 @@ class Schedule { } } - bool isScheduleInDays(unsigned int msk) { + bool isScheduleInDays(ScheduleConfigurationType msk) { if(isScheduleFixed(msk)) { return (getScheduleUnit(msk) == ScheduleUnit::Days) ? true : false ; } else { @@ -297,11 +300,11 @@ class Schedule { return ptm->tm_mon; } - bool checkTimeValid(unsigned int now) { + bool checkTimeValid(ScheduleTimeType now) { return (now != 0); } - bool checkSchedulePeriod(unsigned int now, unsigned int frm, unsigned int to) { + bool checkSchedulePeriod(ScheduleTimeType now, ScheduleTimeType frm, ScheduleTimeType to) { /* Check if current time is inside the schedule period. If 'to' is equal to * 0 the schedule has no end. */ @@ -312,7 +315,7 @@ class Schedule { } } - bool checkScheduleMask(unsigned int now, unsigned int msk) { + bool checkScheduleMask(ScheduleTimeType now, ScheduleConfigurationType msk) { if(isScheduleFixed(msk) || isScheduleOneShot(msk)) { return true; } @@ -349,7 +352,7 @@ class Schedule { return false; } - unsigned int getScheduleDelta(unsigned int msk) { + ScheduleTimeType getScheduleDelta(ScheduleConfigurationType msk) { if(isScheduleInSeconds(msk)) { return SECONDS * getScheduleRepetition(msk); } From d42e419fd7caa19a8be4f6f7c685ca7c68d60ef4 Mon Sep 17 00:00:00 2001 From: pennam Date: Tue, 30 Nov 2021 15:07:09 +0100 Subject: [PATCH 25/27] Move TimeService::getLocalTime() into CloudSchedule test file to make more clear how the time is configured --- extras/test/src/test_CloudSchedule.cpp | 2 +- extras/test/src/util/PropertyTestUtil.cpp | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/extras/test/src/test_CloudSchedule.cpp b/extras/test/src/test_CloudSchedule.cpp index aba4aad0f..53b582aef 100644 --- a/extras/test/src/test_CloudSchedule.cpp +++ b/extras/test/src/test_CloudSchedule.cpp @@ -22,7 +22,7 @@ TimeService::TimeService() {} * TimeService Fake Methods **************************************************************************************/ -unsigned long TimeService::getTime() {return time_now;} +unsigned long TimeService::getLocalTime() {return time_now;} /************************************************************************************** TEST CODE diff --git a/extras/test/src/util/PropertyTestUtil.cpp b/extras/test/src/util/PropertyTestUtil.cpp index ef6d85a99..a4b4e0345 100644 --- a/extras/test/src/util/PropertyTestUtil.cpp +++ b/extras/test/src/util/PropertyTestUtil.cpp @@ -19,11 +19,6 @@ unsigned long getTime() return 0; } -unsigned long TimeService::getLocalTime() -{ - return getTime(); -} - TimeService* ArduinoIoTCloudTimeService() { static TimeService _timeService_instance; return &_timeService_instance; From 71059d045269c8e21bdfc4f6250e2d6aa30c1c65 Mon Sep 17 00:00:00 2001 From: pennam Date: Tue, 30 Nov 2021 14:01:23 +0100 Subject: [PATCH 26/27] Make ArduinoIoTCloudTimeService return a reference instead of a pointer --- extras/test/src/util/PropertyTestUtil.cpp | 4 ++-- src/ArduinoIoTCloud.h | 8 ++++---- src/ArduinoIoTCloudLPWAN.cpp | 4 ++-- src/ArduinoIoTCloudTCP.cpp | 8 ++++---- src/property/types/CloudSchedule.h | 4 ++-- src/utility/time/TimeService.cpp | 4 ++-- src/utility/time/TimeService.h | 2 +- 7 files changed, 17 insertions(+), 17 deletions(-) diff --git a/extras/test/src/util/PropertyTestUtil.cpp b/extras/test/src/util/PropertyTestUtil.cpp index a4b4e0345..ca71cd765 100644 --- a/extras/test/src/util/PropertyTestUtil.cpp +++ b/extras/test/src/util/PropertyTestUtil.cpp @@ -19,7 +19,7 @@ unsigned long getTime() return 0; } -TimeService* ArduinoIoTCloudTimeService() { +TimeService & ArduinoIoTCloudTimeService() { static TimeService _timeService_instance; - return &_timeService_instance; + return _timeService_instance; } diff --git a/src/ArduinoIoTCloud.h b/src/ArduinoIoTCloud.h index 5041bc359..b73cd1cf9 100644 --- a/src/ArduinoIoTCloud.h +++ b/src/ArduinoIoTCloud.h @@ -97,9 +97,9 @@ class ArduinoIoTCloudClass inline ConnectionHandler * getConnection() { return _connection; } - inline unsigned long getInternalTime() { return _time_service->getTime(); } - inline unsigned long getLocalTime() { return _time_service->getLocalTime(); } - inline void updateInternalTimezoneInfo() { _time_service->setTimeZoneData(_tz_offset, _tz_dst_until); } + inline unsigned long getInternalTime() { return _time_service.getTime(); } + inline unsigned long getLocalTime() { return _time_service.getLocalTime(); } + inline void updateInternalTimezoneInfo() { _time_service.setTimeZoneData(_tz_offset, _tz_dst_until); } void addCallback(ArduinoIoTCloudEvent const event, OnCloudEventCallback callback); @@ -147,7 +147,7 @@ class ArduinoIoTCloudClass ConnectionHandler * _connection = nullptr; PropertyContainer _property_container; - TimeService * _time_service = ArduinoIoTCloudTimeService(); + TimeService & _time_service = ArduinoIoTCloudTimeService(); int _tz_offset = 0; unsigned int _tz_dst_until = 0; diff --git a/src/ArduinoIoTCloudLPWAN.cpp b/src/ArduinoIoTCloudLPWAN.cpp index 17da1f651..29458f21a 100644 --- a/src/ArduinoIoTCloudLPWAN.cpp +++ b/src/ArduinoIoTCloudLPWAN.cpp @@ -68,7 +68,7 @@ int ArduinoIoTCloudLPWAN::begin(ConnectionHandler& connection, bool retry) { _connection = &connection; _retryEnable = retry; - _time_service->begin(nullptr); + _time_service.begin(nullptr); return 1; } @@ -105,7 +105,7 @@ ArduinoIoTCloudLPWAN::State ArduinoIoTCloudLPWAN::handle_ConnectPhy() ArduinoIoTCloudLPWAN::State ArduinoIoTCloudLPWAN::handle_SyncTime() { - unsigned long const internal_posix_time = _time_service->getTime(); + unsigned long const internal_posix_time = _time_service.getTime(); DEBUG_VERBOSE("ArduinoIoTCloudLPWAN::%s internal clock configured to posix timestamp %d", __FUNCTION__, internal_posix_time); DEBUG_INFO("Connected to Arduino IoT Cloud"); return State::Connected; diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index c4e469e53..11245ea85 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -115,7 +115,7 @@ int ArduinoIoTCloudTCP::begin(ConnectionHandler & connection, bool const enable_ _connection = &connection; _brokerAddress = brokerAddress; _brokerPort = brokerPort; - _time_service->begin(&connection); + _time_service.begin(&connection); return begin(enable_watchdog, _brokerAddress, _brokerPort); } @@ -371,7 +371,7 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_ConnectPhy() ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SyncTime() { - unsigned long const internal_posix_time = _time_service->getTime(); + unsigned long const internal_posix_time = _time_service.getTime(); DEBUG_VERBOSE("ArduinoIoTCloudTCP::%s internal clock configured to posix timestamp %d", __FUNCTION__, internal_posix_time); return State::ConnectMqttBroker; } @@ -535,7 +535,7 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_Connected() */ sendPropertiesToCloud(); - unsigned long const internal_posix_time = _time_service->getTime(); + unsigned long const internal_posix_time = _time_service.getTime(); if(internal_posix_time < _tz_dst_until) { return State::Connected; } else { @@ -568,7 +568,7 @@ void ArduinoIoTCloudTCP::handleMessage(int length) DEBUG_VERBOSE("ArduinoIoTCloudTCP::%s [%d] last values received", __FUNCTION__, millis()); CBORDecoder::decode(_property_container, (uint8_t*)bytes, length, true); sendPropertiesToCloud(); - _time_service->setTimeZoneData(_tz_offset, _tz_dst_until); + _time_service.setTimeZoneData(_tz_offset, _tz_dst_until); execCloudEventCallback(ArduinoIoTCloudEvent::SYNC); _last_sync_request_cnt = 0; _last_sync_request_tick = 0; diff --git a/src/property/types/CloudSchedule.h b/src/property/types/CloudSchedule.h index 0dcdf4cf6..93090c507 100644 --- a/src/property/types/CloudSchedule.h +++ b/src/property/types/CloudSchedule.h @@ -115,7 +115,7 @@ class Schedule { bool isActive() { - ScheduleTimeType now = _schedule_time_service->getLocalTime(); + ScheduleTimeType now = _schedule_time_service.getLocalTime(); if(checkTimeValid(now)) { /* We have to wait RTC configuration and Timezone setting from the cloud */ @@ -201,7 +201,7 @@ class Schedule { return !(operator==(aSchedule)); } private: - TimeService * _schedule_time_service = ArduinoIoTCloudTimeService(); + TimeService & _schedule_time_service = ArduinoIoTCloudTimeService(); ScheduleUnit getScheduleUnit(ScheduleConfigurationType msk) { return static_cast((msk & SCHEDULE_UNIT_MASK) >> SCHEDULE_UNIT_SHIFT); diff --git a/src/utility/time/TimeService.cpp b/src/utility/time/TimeService.cpp index 83b9bc4e9..112745d06 100644 --- a/src/utility/time/TimeService.cpp +++ b/src/utility/time/TimeService.cpp @@ -268,7 +268,7 @@ time_t cvt_time(char const * time) return mktime(&t); } -TimeService* ArduinoIoTCloudTimeService() { +TimeService & ArduinoIoTCloudTimeService() { static TimeService _timeService_instance; - return &_timeService_instance; + return _timeService_instance; } diff --git a/src/utility/time/TimeService.h b/src/utility/time/TimeService.h index 88b3ca986..fbe81986d 100644 --- a/src/utility/time/TimeService.h +++ b/src/utility/time/TimeService.h @@ -68,6 +68,6 @@ class TimeService }; -TimeService* ArduinoIoTCloudTimeService(); +TimeService & ArduinoIoTCloudTimeService(); #endif /* ARDUINO_IOT_CLOUD_TIME_SERVICE_H_ */ From fda11b53c9373a7f4c5b5fdcef2100042b964873 Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 2 Dec 2021 07:06:56 +0100 Subject: [PATCH 27/27] Add ArduinoIoTCloudClass CTOR and initialize variables in it --- src/ArduinoIoTCloud.cpp | 16 ++++++++++++++++ src/ArduinoIoTCloud.h | 15 ++++++++------- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/ArduinoIoTCloud.cpp b/src/ArduinoIoTCloud.cpp index 5b5637eb3..b62a91990 100644 --- a/src/ArduinoIoTCloud.cpp +++ b/src/ArduinoIoTCloud.cpp @@ -21,6 +21,22 @@ #include +/****************************************************************************** + CTOR/DTOR + ******************************************************************************/ + +ArduinoIoTCloudClass::ArduinoIoTCloudClass() +: _connection{nullptr} +, _time_service(ArduinoIoTCloudTimeService()) +, _tz_offset{0} +, _tz_dst_until{0} +, _thing_id{""} +, _device_id{""} +, _cloud_event_callback{nullptr} +{ + +} + /****************************************************************************** * PUBLIC MEMBER FUNCTIONS ******************************************************************************/ diff --git a/src/ArduinoIoTCloud.h b/src/ArduinoIoTCloud.h index b73cd1cf9..ae8ac1a86 100644 --- a/src/ArduinoIoTCloud.h +++ b/src/ArduinoIoTCloud.h @@ -80,6 +80,7 @@ class ArduinoIoTCloudClass { public: + ArduinoIoTCloudClass(); virtual ~ArduinoIoTCloudClass() { } @@ -145,19 +146,19 @@ class ArduinoIoTCloudClass protected: - ConnectionHandler * _connection = nullptr; + ConnectionHandler * _connection; PropertyContainer _property_container; - TimeService & _time_service = ArduinoIoTCloudTimeService(); - int _tz_offset = 0; - unsigned int _tz_dst_until = 0; + TimeService & _time_service; + int _tz_offset; + unsigned int _tz_dst_until; void execCloudEventCallback(ArduinoIoTCloudEvent const event); private: - String _thing_id = ""; - String _device_id = ""; - OnCloudEventCallback _cloud_event_callback[3] = {nullptr}; + String _thing_id; + String _device_id; + OnCloudEventCallback _cloud_event_callback[3]; }; #ifdef HAS_TCP