Skip to content

Commit c5a59b7

Browse files
authored
Merge pull request #440 from arduino-libraries/callback-remove
Remove public functions to handle thing_id and timezone
2 parents 3de5e41 + b629c11 commit c5a59b7

10 files changed

+134
-37
lines changed

extras/test/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ set(TEST_SRCS
4141
src/test_publishOnChangeRateLimit.cpp
4242
src/test_readOnly.cpp
4343
src/test_writeOnly.cpp
44+
src/test_writeOnDemand.cpp
45+
src/test_writeOnChange.cpp
4446
)
4547

4648
set(TEST_UTIL_SRCS
+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
Copyright (c) 2019 Arduino. All rights reserved.
3+
*/
4+
5+
/**************************************************************************************
6+
INCLUDE
7+
**************************************************************************************/
8+
9+
#include <catch.hpp>
10+
11+
#include <util/CBORTestUtil.h>
12+
13+
#include <CBORDecoder.h>
14+
#include <PropertyContainer.h>
15+
16+
/**************************************************************************************
17+
TEST CODE
18+
**************************************************************************************/
19+
20+
SCENARIO("An Arduino cloud property is marked 'write on change'", "[ArduinoCloudThing::decode]")
21+
{
22+
PropertyContainer property_container;
23+
24+
CloudInt test = 0;
25+
addPropertyToContainer(property_container, test, "test", Permission::ReadWrite).writeOnChange();
26+
27+
/* [{0: "test", 2: 7}] = 81 A2 00 64 74 65 73 74 02 07 */
28+
uint8_t const payload[] = {0x81, 0xA2, 0x00, 0x64, 0x74, 0x65, 0x73, 0x74, 0x02, 0x07};
29+
int const payload_length = sizeof(payload) / sizeof(uint8_t);
30+
CBORDecoder::decode(property_container, payload, payload_length);
31+
32+
REQUIRE(test == 7);
33+
}
+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
Copyright (c) 2019 Arduino. All rights reserved.
3+
*/
4+
5+
/**************************************************************************************
6+
INCLUDE
7+
**************************************************************************************/
8+
9+
#include <catch.hpp>
10+
11+
#include <util/CBORTestUtil.h>
12+
13+
#include <CBORDecoder.h>
14+
#include <PropertyContainer.h>
15+
16+
/**************************************************************************************
17+
TEST CODE
18+
**************************************************************************************/
19+
20+
SCENARIO("An Arduino cloud property is marked 'write on demand'", "[ArduinoCloudThing::decode]")
21+
{
22+
PropertyContainer property_container;
23+
24+
CloudInt test = 0;
25+
addPropertyToContainer(property_container, test, "test", Permission::ReadWrite).writeOnDemand();
26+
27+
/* [{0: "test", 2: 7}] = 81 A2 00 64 74 65 73 74 02 07 */
28+
uint8_t const payload[] = {0x81, 0xA2, 0x00, 0x64, 0x74, 0x65, 0x73, 0x74, 0x02, 0x07};
29+
int const payload_length = sizeof(payload) / sizeof(uint8_t);
30+
CBORDecoder::decode(property_container, payload, payload_length);
31+
32+
REQUIRE(test == 0);
33+
34+
Property* p = getProperty(property_container, "test");
35+
p->fromCloudToLocal();
36+
37+
REQUIRE(test == 7);
38+
}

src/ArduinoIoTCloud.cpp

+1-3
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,11 @@ ArduinoIoTCloudClass::ArduinoIoTCloudClass()
2929
: _connection{nullptr}
3030
, _last_checked_property_index{0}
3131
, _time_service(TimeService)
32-
, _tz_offset{0}
33-
, _tz_dst_until{0}
3432
, _thing_id{""}
33+
, _thing_id_property{nullptr}
3534
, _lib_version{AIOT_CONFIG_LIB_VERSION}
3635
, _device_id{""}
3736
, _cloud_event_callback{nullptr}
38-
, _thing_id_outdated{false}
3937
{
4038

4139
}

src/ArduinoIoTCloud.h

+1-10
Original file line numberDiff line numberDiff line change
@@ -96,17 +96,10 @@ class ArduinoIoTCloudClass
9696
inline void setDeviceId(String const device_id) { _device_id = device_id; };
9797
inline String & getDeviceId() { return _device_id; };
9898

99-
inline void setThingIdOutdatedFlag() { _thing_id_outdated = true ; }
100-
inline void clrThingIdOutdatedFlag() { _thing_id_outdated = false ; }
101-
inline bool getThingIdOutdatedFlag() { return _thing_id_outdated; }
102-
103-
inline bool deviceNotAttached() { return _thing_id == ""; }
104-
10599
inline ConnectionHandler * getConnection() { return _connection; }
106100

107101
inline unsigned long getInternalTime() { return _time_service.getTime(); }
108102
inline unsigned long getLocalTime() { return _time_service.getLocalTime(); }
109-
inline void updateInternalTimezoneInfo() { _time_service.setTimeZoneData(_tz_offset, _tz_dst_until); }
110103

111104
void addCallback(ArduinoIoTCloudEvent const event, OnCloudEventCallback callback);
112105

@@ -157,9 +150,8 @@ class ArduinoIoTCloudClass
157150
PropertyContainer _thing_property_container;
158151
unsigned int _last_checked_property_index;
159152
TimeServiceClass & _time_service;
160-
int _tz_offset;
161-
unsigned int _tz_dst_until;
162153
String _thing_id;
154+
Property * _thing_id_property;
163155
String _lib_version;
164156

165157
void execCloudEventCallback(ArduinoIoTCloudEvent const event);
@@ -170,7 +162,6 @@ class ArduinoIoTCloudClass
170162

171163
String _device_id;
172164
OnCloudEventCallback _cloud_event_callback[3];
173-
bool _thing_id_outdated;
174165
};
175166

176167
#ifdef HAS_TCP

src/ArduinoIoTCloudTCP.cpp

+27-22
Original file line numberDiff line numberDiff line change
@@ -53,22 +53,16 @@ unsigned long getTime()
5353
return ArduinoCloud.getInternalTime();
5454
}
5555

56-
void updateTimezoneInfo()
57-
{
58-
ArduinoCloud.updateInternalTimezoneInfo();
59-
}
60-
61-
void setThingIdOutdated()
62-
{
63-
ArduinoCloud.setThingIdOutdatedFlag();
64-
}
65-
6656
/******************************************************************************
6757
CTOR/DTOR
6858
******************************************************************************/
6959

7060
ArduinoIoTCloudTCP::ArduinoIoTCloudTCP()
7161
: _state{State::ConnectPhy}
62+
, _tz_offset{0}
63+
, _tz_offset_property{nullptr}
64+
, _tz_dst_until{0}
65+
, _tz_dst_until_property{nullptr}
7266
, _next_connection_attempt_tick{0}
7367
, _last_connection_attempt_cnt{0}
7468
, _next_device_subscribe_attempt_tick{0}
@@ -218,10 +212,11 @@ int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress,
218212
addPropertyToContainer(_device_property_container, *p, "OTA_REQ", Permission::ReadWrite, -1);
219213
#endif /* OTA_ENABLED */
220214
p = new CloudWrapperString(_thing_id);
221-
addPropertyToContainer(_device_property_container, *p, "thing_id", Permission::ReadWrite, -1).onUpdate(setThingIdOutdated);
222-
223-
addPropertyReal(_tz_offset, "tz_offset", Permission::ReadWrite).onSync(CLOUD_WINS).onUpdate(updateTimezoneInfo);
224-
addPropertyReal(_tz_dst_until, "tz_dst_until", Permission::ReadWrite).onSync(CLOUD_WINS).onUpdate(updateTimezoneInfo);
215+
_thing_id_property = &addPropertyToContainer(_device_property_container, *p, "thing_id", Permission::ReadWrite, -1).writeOnDemand();
216+
p = new CloudWrapperInt(_tz_offset);
217+
_tz_offset_property = &addPropertyToContainer(_thing_property_container, *p, "tz_offset", Permission::ReadWrite, -1).writeOnDemand();
218+
p = new CloudWrapperUnsignedInt(_tz_dst_until);
219+
_tz_dst_until_property = &addPropertyToContainer(_thing_property_container, *p, "tz_dst_until", Permission::ReadWrite, -1).writeOnDemand();
225220

226221
#if OTA_ENABLED
227222
_ota_cap = OTA::isCapable();
@@ -409,7 +404,7 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_WaitDeviceConfig()
409404
return State::Disconnect;
410405
}
411406

412-
if (getThingIdOutdatedFlag())
407+
if (_thing_id_property->isDifferentFromCloud())
413408
{
414409
return State::CheckDeviceConfig;
415410
}
@@ -445,7 +440,7 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_CheckDeviceConfig()
445440

446441
updateThingTopics();
447442

448-
if (deviceNotAttached())
443+
if (_thing_id.length() == 0)
449444
{
450445
/* Configuration received but device not attached. Wait: 40s */
451446
unsigned long attach_retry_delay = (1 << _last_device_attach_cnt) * AIOT_CONFIG_DEVICE_TOPIC_SUBSCRIBE_RETRY_DELAY_ms;
@@ -468,7 +463,7 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SubscribeThingTopics()
468463
return State::Disconnect;
469464
}
470465

471-
if (getThingIdOutdatedFlag())
466+
if (_thing_id_property->isDifferentFromCloud())
472467
{
473468
return State::CheckDeviceConfig;
474469
}
@@ -524,7 +519,7 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_RequestLastValues()
524519
return State::Disconnect;
525520
}
526521

527-
if (getThingIdOutdatedFlag())
522+
if (_thing_id_property->isDifferentFromCloud())
528523
{
529524
return State::CheckDeviceConfig;
530525
}
@@ -567,7 +562,7 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_Connected()
567562
/* We are connected so let's to our stuff here. */
568563
else
569564
{
570-
if (getThingIdOutdatedFlag())
565+
if (_thing_id_property->isDifferentFromCloud())
571566
{
572567
return State::CheckDeviceConfig;
573568
}
@@ -589,13 +584,23 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_Connected()
589584
_mqtt_data_request_retransmit = false;
590585
}
591586

587+
/* Configure Time service with timezone data:
588+
* _tz_offset [offset + dst]
589+
* _tz_dst_until [posix timestamp until _tz_offset is valid]
590+
*/
591+
if (_tz_offset_property->isDifferentFromCloud() || _tz_dst_until_property->isDifferentFromCloud()) {
592+
_tz_offset_property->fromCloudToLocal();
593+
_tz_dst_until_property->fromCloudToLocal();
594+
_time_service.setTimeZoneData(_tz_offset, _tz_dst_until);
595+
}
596+
592597
/* Check if any properties need encoding and send them to
593598
* the cloud if necessary.
594599
*/
595600
sendThingPropertiesToCloud();
596601

597602
unsigned long const internal_posix_time = _time_service.getTime();
598-
if(internal_posix_time < _tz_dst_until) {
603+
if (internal_posix_time < _tz_dst_until) {
599604
return State::Connected;
600605
} else {
601606
return State::RequestLastValues;
@@ -762,12 +767,12 @@ int ArduinoIoTCloudTCP::write(String const topic, byte const data[], int const l
762767

763768
void ArduinoIoTCloudTCP::updateThingTopics()
764769
{
770+
_thing_id_property->fromCloudToLocal();
771+
765772
_shadowTopicOut = getTopic_shadowout();
766773
_shadowTopicIn = getTopic_shadowin();
767774
_dataTopicOut = getTopic_dataout();
768775
_dataTopicIn = getTopic_datain();
769-
770-
clrThingIdOutdatedFlag();
771776
}
772777

773778
/******************************************************************************

src/ArduinoIoTCloudTCP.h

+5
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,11 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass
123123

124124
State _state;
125125

126+
int _tz_offset;
127+
Property * _tz_offset_property;
128+
unsigned int _tz_dst_until;
129+
Property * _tz_dst_until_property;
130+
126131
unsigned long _next_connection_attempt_tick;
127132
unsigned int _last_connection_attempt_cnt;
128133
unsigned long _next_device_subscribe_attempt_tick;

src/property/Property.cpp

+13
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ Property::Property()
2929
, _min_delta_property{0.0f}
3030
, _min_time_between_updates_millis{DEFAULT_MIN_TIME_BETWEEN_UPDATES_MILLIS}
3131
, _permission{Permission::Read}
32+
, _write_policy{WritePolicy::Auto}
3233
, _get_time_func{nullptr}
3334
, _update_callback_func{nullptr}
3435
, _on_sync_callback_func{nullptr}
@@ -102,6 +103,18 @@ Property & Property::encodeTimestamp()
102103
return (*this);
103104
}
104105

106+
Property & Property::writeOnChange()
107+
{
108+
_write_policy = WritePolicy::Auto;
109+
return (*this);
110+
}
111+
112+
Property & Property::writeOnDemand()
113+
{
114+
_write_policy = WritePolicy::Manual;
115+
return (*this);
116+
}
117+
105118
void Property::setTimestamp(unsigned long const timestamp)
106119
{
107120
_timestamp = timestamp;

src/property/Property.h

+11-1
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,10 @@ enum class UpdatePolicy {
125125
OnChange, TimeInterval, OnDemand
126126
};
127127

128+
enum class WritePolicy {
129+
Auto, Manual
130+
};
131+
128132
typedef void(*UpdateCallbackFunc)(void);
129133
typedef unsigned long(*GetTimeCallbackFunc)();
130134
class Property;
@@ -147,6 +151,8 @@ class Property
147151
Property & publishEvery(unsigned long const seconds);
148152
Property & publishOnDemand();
149153
Property & encodeTimestamp();
154+
Property & writeOnChange();
155+
Property & writeOnDemand();
150156

151157
inline String name() const {
152158
return _name;
@@ -160,6 +166,9 @@ class Property
160166
inline bool isWriteableByCloud() const {
161167
return (_permission == Permission::Write) || (_permission == Permission::ReadWrite);
162168
}
169+
inline bool isWritableOnChange() const {
170+
return _write_policy == WritePolicy::Auto;
171+
}
163172

164173
void setTimestamp(unsigned long const timestamp);
165174
bool shouldBeUpdated();
@@ -209,6 +218,7 @@ class Property
209218

210219
private:
211220
Permission _permission;
221+
WritePolicy _write_policy;
212222
GetTimeCallbackFunc _get_time_func;
213223
UpdateCallbackFunc _update_callback_func;
214224
OnSyncCallbackFunc _on_sync_callback_func;
@@ -219,7 +229,7 @@ class Property
219229
_has_been_appended_but_not_sended;
220230
/* Variables used for UpdatePolicy::TimeInterval */
221231
unsigned long _last_updated_millis,
222-
_update_interval_millis;
232+
_update_interval_millis;
223233
/* Variables used for reconnection sync*/
224234
unsigned long _last_local_change_timestamp;
225235
unsigned long _last_cloud_change_timestamp;

src/property/PropertyContainer.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,9 @@ void updateProperty(PropertyContainer & prop_cont, String propertyName, unsigned
121121
if (is_sync_message) {
122122
property->execCallbackOnSync();
123123
} else {
124-
property->fromCloudToLocal();
124+
if (property->isWritableOnChange()) {
125+
property->fromCloudToLocal();
126+
}
125127
property->execCallbackOnChange();
126128
property->provideEcho();
127129
}

0 commit comments

Comments
 (0)