Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove public functions to handle thing_id and timezone #440

Merged
merged 6 commits into from
May 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions extras/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ set(TEST_SRCS
src/test_publishOnChangeRateLimit.cpp
src/test_readOnly.cpp
src/test_writeOnly.cpp
src/test_writeOnDemand.cpp
src/test_writeOnChange.cpp
)

set(TEST_UTIL_SRCS
Expand Down
33 changes: 33 additions & 0 deletions extras/test/src/test_writeOnChange.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
Copyright (c) 2019 Arduino. All rights reserved.
*/

/**************************************************************************************
INCLUDE
**************************************************************************************/

#include <catch.hpp>

#include <util/CBORTestUtil.h>

#include <CBORDecoder.h>
#include <PropertyContainer.h>

/**************************************************************************************
TEST CODE
**************************************************************************************/

SCENARIO("An Arduino cloud property is marked 'write on change'", "[ArduinoCloudThing::decode]")
{
PropertyContainer property_container;

CloudInt test = 0;
addPropertyToContainer(property_container, test, "test", Permission::ReadWrite).writeOnChange();

/* [{0: "test", 2: 7}] = 81 A2 00 64 74 65 73 74 02 07 */
uint8_t const payload[] = {0x81, 0xA2, 0x00, 0x64, 0x74, 0x65, 0x73, 0x74, 0x02, 0x07};
int const payload_length = sizeof(payload) / sizeof(uint8_t);
CBORDecoder::decode(property_container, payload, payload_length);

REQUIRE(test == 7);
}
38 changes: 38 additions & 0 deletions extras/test/src/test_writeOnDemand.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
Copyright (c) 2019 Arduino. All rights reserved.
*/

/**************************************************************************************
INCLUDE
**************************************************************************************/

#include <catch.hpp>

#include <util/CBORTestUtil.h>

#include <CBORDecoder.h>
#include <PropertyContainer.h>

/**************************************************************************************
TEST CODE
**************************************************************************************/

SCENARIO("An Arduino cloud property is marked 'write on demand'", "[ArduinoCloudThing::decode]")
{
PropertyContainer property_container;

CloudInt test = 0;
addPropertyToContainer(property_container, test, "test", Permission::ReadWrite).writeOnDemand();

/* [{0: "test", 2: 7}] = 81 A2 00 64 74 65 73 74 02 07 */
uint8_t const payload[] = {0x81, 0xA2, 0x00, 0x64, 0x74, 0x65, 0x73, 0x74, 0x02, 0x07};
int const payload_length = sizeof(payload) / sizeof(uint8_t);
CBORDecoder::decode(property_container, payload, payload_length);

REQUIRE(test == 0);

Property* p = getProperty(property_container, "test");
p->fromCloudToLocal();

REQUIRE(test == 7);
}
4 changes: 1 addition & 3 deletions src/ArduinoIoTCloud.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,11 @@ ArduinoIoTCloudClass::ArduinoIoTCloudClass()
: _connection{nullptr}
, _last_checked_property_index{0}
, _time_service(TimeService)
, _tz_offset{0}
, _tz_dst_until{0}
, _thing_id{""}
, _thing_id_property{nullptr}
, _lib_version{AIOT_CONFIG_LIB_VERSION}
, _device_id{""}
, _cloud_event_callback{nullptr}
, _thing_id_outdated{false}
{

}
Expand Down
11 changes: 1 addition & 10 deletions src/ArduinoIoTCloud.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,17 +96,10 @@ class ArduinoIoTCloudClass
inline void setDeviceId(String const device_id) { _device_id = device_id; };
inline String & getDeviceId() { return _device_id; };

inline void setThingIdOutdatedFlag() { _thing_id_outdated = true ; }
inline void clrThingIdOutdatedFlag() { _thing_id_outdated = false ; }
inline bool getThingIdOutdatedFlag() { return _thing_id_outdated; }

inline bool deviceNotAttached() { return _thing_id == ""; }

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); }

void addCallback(ArduinoIoTCloudEvent const event, OnCloudEventCallback callback);

Expand Down Expand Up @@ -157,9 +150,8 @@ class ArduinoIoTCloudClass
PropertyContainer _thing_property_container;
unsigned int _last_checked_property_index;
TimeServiceClass & _time_service;
int _tz_offset;
unsigned int _tz_dst_until;
String _thing_id;
Property * _thing_id_property;
String _lib_version;

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

String _device_id;
OnCloudEventCallback _cloud_event_callback[3];
bool _thing_id_outdated;
};

#ifdef HAS_TCP
Expand Down
49 changes: 27 additions & 22 deletions src/ArduinoIoTCloudTCP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,22 +53,16 @@ unsigned long getTime()
return ArduinoCloud.getInternalTime();
}

void updateTimezoneInfo()
{
ArduinoCloud.updateInternalTimezoneInfo();
}

void setThingIdOutdated()
{
ArduinoCloud.setThingIdOutdatedFlag();
}

/******************************************************************************
CTOR/DTOR
******************************************************************************/

ArduinoIoTCloudTCP::ArduinoIoTCloudTCP()
: _state{State::ConnectPhy}
, _tz_offset{0}
, _tz_offset_property{nullptr}
, _tz_dst_until{0}
, _tz_dst_until_property{nullptr}
, _next_connection_attempt_tick{0}
, _last_connection_attempt_cnt{0}
, _next_device_subscribe_attempt_tick{0}
Expand Down Expand Up @@ -218,10 +212,11 @@ int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress,
addPropertyToContainer(_device_property_container, *p, "OTA_REQ", Permission::ReadWrite, -1);
#endif /* OTA_ENABLED */
p = new CloudWrapperString(_thing_id);
addPropertyToContainer(_device_property_container, *p, "thing_id", Permission::ReadWrite, -1).onUpdate(setThingIdOutdated);

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);
_thing_id_property = &addPropertyToContainer(_device_property_container, *p, "thing_id", Permission::ReadWrite, -1).writeOnDemand();
p = new CloudWrapperInt(_tz_offset);
_tz_offset_property = &addPropertyToContainer(_thing_property_container, *p, "tz_offset", Permission::ReadWrite, -1).writeOnDemand();
p = new CloudWrapperUnsignedInt(_tz_dst_until);
_tz_dst_until_property = &addPropertyToContainer(_thing_property_container, *p, "tz_dst_until", Permission::ReadWrite, -1).writeOnDemand();

#if OTA_ENABLED
_ota_cap = OTA::isCapable();
Expand Down Expand Up @@ -409,7 +404,7 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_WaitDeviceConfig()
return State::Disconnect;
}

if (getThingIdOutdatedFlag())
if (_thing_id_property->isDifferentFromCloud())
{
return State::CheckDeviceConfig;
}
Expand Down Expand Up @@ -445,7 +440,7 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_CheckDeviceConfig()

updateThingTopics();

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

if (getThingIdOutdatedFlag())
if (_thing_id_property->isDifferentFromCloud())
{
return State::CheckDeviceConfig;
}
Expand Down Expand Up @@ -524,7 +519,7 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_RequestLastValues()
return State::Disconnect;
}

if (getThingIdOutdatedFlag())
if (_thing_id_property->isDifferentFromCloud())
{
return State::CheckDeviceConfig;
}
Expand Down Expand Up @@ -567,7 +562,7 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_Connected()
/* We are connected so let's to our stuff here. */
else
{
if (getThingIdOutdatedFlag())
if (_thing_id_property->isDifferentFromCloud())
{
return State::CheckDeviceConfig;
}
Expand All @@ -589,13 +584,23 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_Connected()
_mqtt_data_request_retransmit = false;
}

/* Configure Time service with timezone data:
* _tz_offset [offset + dst]
* _tz_dst_until [posix timestamp until _tz_offset is valid]
*/
if (_tz_offset_property->isDifferentFromCloud() || _tz_dst_until_property->isDifferentFromCloud()) {
_tz_offset_property->fromCloudToLocal();
_tz_dst_until_property->fromCloudToLocal();
_time_service.setTimeZoneData(_tz_offset, _tz_dst_until);
}

/* Check if any properties need encoding and send them to
* the cloud if necessary.
*/
sendThingPropertiesToCloud();

unsigned long const internal_posix_time = _time_service.getTime();
if(internal_posix_time < _tz_dst_until) {
if (internal_posix_time < _tz_dst_until) {
return State::Connected;
} else {
return State::RequestLastValues;
Expand Down Expand Up @@ -762,12 +767,12 @@ int ArduinoIoTCloudTCP::write(String const topic, byte const data[], int const l

void ArduinoIoTCloudTCP::updateThingTopics()
{
_thing_id_property->fromCloudToLocal();

_shadowTopicOut = getTopic_shadowout();
_shadowTopicIn = getTopic_shadowin();
_dataTopicOut = getTopic_dataout();
_dataTopicIn = getTopic_datain();

clrThingIdOutdatedFlag();
}

/******************************************************************************
Expand Down
5 changes: 5 additions & 0 deletions src/ArduinoIoTCloudTCP.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,11 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass

State _state;

int _tz_offset;
Property * _tz_offset_property;
unsigned int _tz_dst_until;
Property * _tz_dst_until_property;

unsigned long _next_connection_attempt_tick;
unsigned int _last_connection_attempt_cnt;
unsigned long _next_device_subscribe_attempt_tick;
Expand Down
13 changes: 13 additions & 0 deletions src/property/Property.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Property::Property()
, _min_delta_property{0.0f}
, _min_time_between_updates_millis{DEFAULT_MIN_TIME_BETWEEN_UPDATES_MILLIS}
, _permission{Permission::Read}
, _write_policy{WritePolicy::Auto}
, _get_time_func{nullptr}
, _update_callback_func{nullptr}
, _on_sync_callback_func{nullptr}
Expand Down Expand Up @@ -102,6 +103,18 @@ Property & Property::encodeTimestamp()
return (*this);
}

Property & Property::writeOnChange()
{
_write_policy = WritePolicy::Auto;
return (*this);
}

Property & Property::writeOnDemand()
{
_write_policy = WritePolicy::Manual;
return (*this);
}

void Property::setTimestamp(unsigned long const timestamp)
{
_timestamp = timestamp;
Expand Down
12 changes: 11 additions & 1 deletion src/property/Property.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@ enum class UpdatePolicy {
OnChange, TimeInterval, OnDemand
};

enum class WritePolicy {
Auto, Manual
};

typedef void(*UpdateCallbackFunc)(void);
typedef unsigned long(*GetTimeCallbackFunc)();
class Property;
Expand All @@ -147,6 +151,8 @@ class Property
Property & publishEvery(unsigned long const seconds);
Property & publishOnDemand();
Property & encodeTimestamp();
Property & writeOnChange();
Property & writeOnDemand();

inline String name() const {
return _name;
Expand All @@ -160,6 +166,9 @@ class Property
inline bool isWriteableByCloud() const {
return (_permission == Permission::Write) || (_permission == Permission::ReadWrite);
}
inline bool isWritableOnChange() const {
return _write_policy == WritePolicy::Auto;
}

void setTimestamp(unsigned long const timestamp);
bool shouldBeUpdated();
Expand Down Expand Up @@ -209,6 +218,7 @@ class Property

private:
Permission _permission;
WritePolicy _write_policy;
GetTimeCallbackFunc _get_time_func;
UpdateCallbackFunc _update_callback_func;
OnSyncCallbackFunc _on_sync_callback_func;
Expand All @@ -219,7 +229,7 @@ class Property
_has_been_appended_but_not_sended;
/* Variables used for UpdatePolicy::TimeInterval */
unsigned long _last_updated_millis,
_update_interval_millis;
_update_interval_millis;
/* Variables used for reconnection sync*/
unsigned long _last_local_change_timestamp;
unsigned long _last_cloud_change_timestamp;
Expand Down
4 changes: 3 additions & 1 deletion src/property/PropertyContainer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,9 @@ void updateProperty(PropertyContainer & prop_cont, String propertyName, unsigned
if (is_sync_message) {
property->execCallbackOnSync();
} else {
property->fromCloudToLocal();
if (property->isWritableOnChange()) {
property->fromCloudToLocal();
}
property->execCallbackOnChange();
property->provideEcho();
}
Expand Down
Loading