Skip to content
This repository was archived by the owner on Aug 18, 2020. It is now read-only.

Commit fe13c5d

Browse files
committed
Bugfix + test code - if a property is manipulated in its onChange callback function to its origin state the change is still propagated to the cloud
1 parent f8e01bc commit fe13c5d

File tree

3 files changed

+54
-3
lines changed

3 files changed

+54
-3
lines changed

src/ArduinoCloudProperty.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ class ArduinoCloudProperty {
7777
inline bool isReadableByCloud () const { return (_permission == Permission::Read ) || (_permission == Permission::ReadWrite); }
7878
inline bool isWriteableByCloud() const { return (_permission == Permission::Write) || (_permission == Permission::ReadWrite); }
7979

80-
bool shouldBeUpdated () const;
80+
bool shouldBeUpdated ();
8181
void execCallbackOnChange ();
8282

8383
void append (CborEncoder * encoder, CloudProtocol const cloud_protocol);
@@ -91,7 +91,8 @@ class ArduinoCloudProperty {
9191
UpdateCallbackFunc _update_callback_func;
9292

9393
UpdatePolicy _update_policy;
94-
bool _has_been_updated_once;
94+
bool _has_been_updated_once,
95+
_has_been_modified_in_callback;
9596
/* Variables used for UpdatePolicy::OnChange */
9697
T _min_delta_property;
9798
unsigned long _min_time_between_updates_millis;

src/ArduinoCloudProperty.ipp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ ArduinoCloudProperty<T>::ArduinoCloudProperty(T & property, String const & name,
1111
_update_callback_func(NULL),
1212
_update_policy(UpdatePolicy::OnChange),
1313
_has_been_updated_once(false),
14+
_has_been_modified_in_callback(false),
1415
_min_delta_property(getInitialMinDeltaPropertyValue()),
1516
_min_time_between_updates_millis(0),
1617
_last_updated_millis(0),
@@ -52,9 +53,14 @@ ArduinoCloudProperty<T> & ArduinoCloudProperty<T>::publishEvery(unsigned long co
5253
}
5354

5455
template <typename T>
55-
bool ArduinoCloudProperty<T>::shouldBeUpdated() const {
56+
bool ArduinoCloudProperty<T>::shouldBeUpdated() {
5657
if(!_has_been_updated_once) return true;
5758

59+
if(_has_been_modified_in_callback) {
60+
_has_been_modified_in_callback = false;
61+
return true;
62+
}
63+
5864
if (_update_policy == UpdatePolicy::OnChange) {
5965
return (isValueDifferent(_property, _shadow_property) && ((millis() - _last_updated_millis) >= (_min_time_between_updates_millis)));
6066
}
@@ -72,6 +78,10 @@ void ArduinoCloudProperty<T>::execCallbackOnChange() {
7278
if(_update_callback_func != NULL) {
7379
_update_callback_func();
7480
}
81+
82+
if(!isValueDifferent(_property, _shadow_property)) {
83+
_has_been_modified_in_callback = true;
84+
}
7585
}
7686
}
7787

test/src/test_callback.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,43 @@ SCENARIO("A callback is registered via 'onUpdate' to be called on property chang
6464

6565
/************************************************************************************/
6666
}
67+
68+
/**************************************************************************************/
69+
70+
static bool switch_turned_on = false;
71+
static bool switch_callback_called = false;
72+
73+
void switch_callback()
74+
{
75+
switch_turned_on = false;
76+
switch_callback_called = true;
77+
}
78+
79+
SCENARIO("A (boolean) property is manipulated in the callback to its origin state", "[ArduinoCloudThing::decode]")
80+
{
81+
GIVEN("CloudProtocol::V1")
82+
{
83+
ArduinoCloudThing thing(CloudProtocol::V1);
84+
thing.begin();
85+
encode(thing);
86+
87+
thing.addPropertyReal(switch_turned_on, "switch_turned_on", Permission::ReadWrite).onUpdate(switch_callback);
88+
89+
/* [{"n": "switch_turned_on", "vb": true}] = 81 A2 61 6E 70 73 77 69 74 63 68 5F 74 75 72 6E 65 64 5F 6F 6E 62 76 62 F5 */
90+
uint8_t const payload[] = {0x81, 0xA2, 0x61, 0x6E, 0x70, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x5F, 0x74, 0x75, 0x72, 0x6E, 0x65, 0x64, 0x5F, 0x6F, 0x6E, 0x62, 0x76, 0x62, 0xF5};
91+
int const payload_length = sizeof(payload)/sizeof(uint8_t);
92+
thing.decode(payload, payload_length);
93+
94+
REQUIRE(switch_callback_called == true);
95+
96+
/* Since the property was reset to its origin state in the callback we
97+
* expect that on the next call to encode this change is propagated to
98+
* the cloud.
99+
*/
100+
101+
/* [{"n": "switch_turned_on", "vb": false}] = 81 BF 61 6E 70 73 77 69 74 63 68 5F 74 75 72 6E 65 64 5F 6F 6E 62 76 62 F4 FF */
102+
std::vector<uint8_t> const expected = {0x81, 0xBF, 0x61, 0x6E, 0x70, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x5F, 0x74, 0x75, 0x72, 0x6E, 0x65, 0x64, 0x5F, 0x6F, 0x6E, 0x62, 0x76, 0x62, 0xF4, 0xFF};
103+
std::vector<uint8_t> const actual = encode(thing);
104+
REQUIRE(actual == expected);
105+
}
106+
}

0 commit comments

Comments
 (0)