Skip to content

Commit 2c0b7fc

Browse files
Commodity tariff example. Using MockClock to provide the test time environment in the example (#41552)
* The Fake time feature in the example app is implemented via MockClock class. Some related fixes in server implementation * The Fake time feature in the example app is implemented via MockClock class. Some related fixes in application * Few fixe by Gemini's notes * Restyler fix * Fixes by CR notes. Bugfix by manual testing * Code style fix * Some updates by CR requests * Improved by Gemini's review notes * Code style fix * Regarded to issue #40911 * Upd by CR request * Ipromements by last CR. Attemts to fix CI fail * small samples fix * Revertad useless change * A small fix to use UnixEpoch time in current attrs. Needs to pass some related python tests * Small style fix * Small style fix * Fixed Unix/Matter time conversion issue * Small style fix * the Utils n/x moved upper * std:arrays replaced to ScopedMem buffs * Revert "std:arrays replaced to ScopedMem buffs" This reverts commit 3cd66e4. * Revert "the Utils n/x moved upper" This reverts commit edb7d41.
1 parent 7bad8a9 commit 2c0b7fc

File tree

5 files changed

+217
-78
lines changed

5 files changed

+217
-78
lines changed

examples/energy-gateway-app/commodity-tariff/include/CommodityTariffInstance.h

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ class CommodityTariffDelegate : public CommodityTariff::Delegate
5252
void CleanupTariffData();
5353
};
5454

55-
class CommodityTariffInstance : public Instance
55+
class CommodityTariffInstance : public CommodityTariff::Instance
5656
{
5757
public:
5858
CommodityTariffInstance(EndpointId aEndpointId, CommodityTariffDelegate & aDelegate, Feature aFeature) :
@@ -72,19 +72,13 @@ class CommodityTariffInstance : public Instance
7272

7373
CommodityTariffDelegate * GetDelegate() { return mCommodityTariffDelegate; };
7474

75-
void ActivateTariffTimeTracking(uint32_t timestamp);
76-
void TariffTimeTrackingSetOffset(uint32_t offset);
77-
7875
private:
7976
CommodityTariffDelegate * mCommodityTariffDelegate;
80-
uint32_t TimestampNow = 0;
81-
uint32_t TestTimeOverlay = 0;
8277

78+
// Private methods for tariff time management
8379
void ScheduleTariffTimeUpdate();
80+
void CancelTariffTimeUpdate();
8481
void TariffTimeUpdCb();
85-
86-
protected:
87-
uint32_t GetCurrentTimestamp() override;
8882
};
8983

9084
} // namespace CommodityTariff

examples/energy-gateway-app/commodity-tariff/src/CommodityTariffEventTriggers.cpp

Lines changed: 178 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,173 @@ using namespace chip::app::Clusters;
2828
using namespace chip::app::Clusters::CommodityTariff;
2929
using namespace chip::app::Clusters::CommodityTariff::Structs;
3030
using namespace chip::app::Clusters::CommodityTariff::TariffDataSamples;
31+
using namespace chip::System;
32+
using namespace chip::System::Clock;
33+
using namespace chip::System::Clock::Literals;
3134

3235
static constexpr uint32_t kSecondsPer4hr = 14400; // 4 hours in seconds
3336

3437
static uint8_t presetIndex = 0;
3538

36-
// Number of presets (compile-time constant)
39+
// Test Time Management Implementation
40+
namespace {
41+
42+
class TestTimeManager
43+
{
44+
public:
45+
TestTimeManager() = default;
46+
~TestTimeManager() { ShutdownMockClock(); }
47+
48+
void EnableTestTime(bool enable, uint32_t aInitialTimeValue_s = 0);
49+
void AdvanceTestTime(chip::System::Clock::Seconds32 offset);
50+
bool IsTestTimeEnabled() const { return mTestTimeEnabled; }
51+
52+
private:
53+
void InitializeMockClock(uint32_t aInitialTimeValue_s = 0);
54+
void ShutdownMockClock();
55+
void AdvanceMockTime(chip::System::Clock::Seconds32 offset);
56+
57+
chip::System::Clock::Internal::MockClock * pMockClock = nullptr;
58+
chip::System::Clock::ClockBase * pRealClock = nullptr;
59+
bool mTestTimeEnabled = false;
60+
};
61+
62+
TestTimeManager gTestTimeManager;
63+
64+
void TestTimeManager::InitializeMockClock(uint32_t aInitialTimeValue_s)
65+
{
66+
// Create and configure the mock clock
67+
pMockClock = new Clock::Internal::MockClock();
68+
pRealClock = &SystemClock();
69+
Microseconds64 realTime_us;
70+
CHIP_ERROR err = CHIP_NO_ERROR;
71+
72+
if (aInitialTimeValue_s == 0)
73+
{
74+
// Get current real time to use as initial mock time
75+
err = chip::System::SystemClock().GetClock_RealTime(realTime_us);
76+
}
77+
else
78+
{
79+
realTime_us = aInitialTimeValue_s * 1'000'000_us; // seconds to microseconds
80+
}
81+
82+
if (err == CHIP_NO_ERROR)
83+
{
84+
pMockClock->SetClock_RealTime(realTime_us);
85+
86+
// Also set monotonic time to maintain consistency
87+
auto monotonicTime = std::chrono::duration_cast<Milliseconds64>(realTime_us);
88+
pMockClock->SetMonotonic(monotonicTime);
89+
90+
ChipLogProgress(DeviceLayer, "Mock clock initialized with current real time");
91+
}
92+
else
93+
{
94+
// Fallback: use a reasonable default time if real time is unavailable
95+
Microseconds64 defaultTime(std::chrono::seconds(1704067200)); // Jan 1, 2024
96+
pMockClock->SetClock_RealTime(defaultTime);
97+
pMockClock->SetMonotonic(std::chrono::duration_cast<Milliseconds64>(defaultTime));
98+
99+
ChipLogProgress(DeviceLayer, "Mock clock initialized with default time");
100+
}
101+
102+
// Install the mock clock globally
103+
Clock::Internal::SetSystemClockForTesting(pMockClock);
104+
}
105+
106+
void TestTimeManager::ShutdownMockClock()
107+
{
108+
if (pMockClock)
109+
{
110+
// Restore the real system clock
111+
Clock::Internal::SetSystemClockForTesting(pRealClock);
112+
delete pMockClock;
113+
pMockClock = nullptr;
114+
}
115+
}
116+
117+
void TestTimeManager::AdvanceMockTime(Seconds32 offset)
118+
{
119+
if (!mTestTimeEnabled || !pMockClock)
120+
{
121+
ChipLogError(DeviceLayer, "Cannot advance time - test time not enabled");
122+
return;
123+
}
124+
125+
// Get current mock time
126+
Microseconds64 currentTime, newTime;
127+
128+
pMockClock->GetClock_RealTime(currentTime);
129+
130+
// Update both real time and monotonic time consistently
131+
pMockClock->AdvanceRealTime(std::chrono::duration_cast<Milliseconds64>(offset));
132+
pMockClock->AdvanceMonotonic(std::chrono::duration_cast<Milliseconds64>(offset));
133+
134+
// Update base time reference
135+
pMockClock->GetClock_RealTime(newTime);
136+
137+
ChipLogProgress(DeviceLayer, "Advanced mock time: %" PRIu32 "s -> %" PRIu32 "s (+%" PRIu32 "s)",
138+
std::chrono::duration_cast<Seconds32>(currentTime).count(),
139+
std::chrono::duration_cast<Seconds32>(newTime).count(), offset.count());
140+
}
141+
142+
void TestTimeManager::EnableTestTime(bool enable, uint32_t aInitialTimeValue_s)
143+
{
144+
if (enable == mTestTimeEnabled)
145+
{
146+
// No change needed, but still trigger updates if re-enabling with same state
147+
if (enable)
148+
{
149+
ChipLogProgress(DeviceLayer, "Test time already enabled");
150+
}
151+
else
152+
{
153+
ChipLogProgress(DeviceLayer, "Test time already disabled");
154+
}
155+
return;
156+
}
157+
158+
if (enable)
159+
{
160+
// Enable test time mode
161+
InitializeMockClock(aInitialTimeValue_s);
162+
mTestTimeEnabled = true;
163+
ChipLogProgress(DeviceLayer, "🔧 Test time mode ENABLED - using mock clock");
164+
}
165+
else
166+
{
167+
// Disable test time mode - this effectively resets to real time
168+
ShutdownMockClock();
169+
mTestTimeEnabled = false;
170+
ChipLogProgress(DeviceLayer, "⏰ Test time mode DISABLED - restored real system clock");
171+
}
172+
}
173+
174+
void TestTimeManager::AdvanceTestTime(Seconds32 offset)
175+
{
176+
if (!mTestTimeEnabled)
177+
{
178+
ChipLogError(DeviceLayer, "Cannot advance time - test time not enabled. Call EnableTestTime(true) first.");
179+
return;
180+
}
181+
182+
if (offset.count() > 0)
183+
{
184+
AdvanceMockTime(offset);
185+
ChipLogProgress(DeviceLayer, "⏩ Time advanced by %" PRIu32 " seconds (%" PRIu32 " minutes, %" PRIu32 " hours)",
186+
offset.count(), offset.count() / 60, offset.count() / 3600);
187+
}
188+
189+
// Trigger tariff time synchronization
190+
CommodityTariffInstance * instance = GetCommodityTariffInstance();
191+
if (instance)
192+
{
193+
instance->TariffTimeAttrsSync();
194+
}
195+
}
196+
197+
} // anonymous namespace
37198

38199
// Safe accessor function
39200
static const TariffDataSet & GetNextPreset()
@@ -47,7 +208,6 @@ void SetTestEventTrigger_TariffDataUpdated()
47208
{
48209
const TariffDataSet & tariff_preset = GetNextPreset();
49210
CommodityTariffDelegate * dg = GetCommodityTariffDelegate();
50-
CommodityTariffInstance * instance = GetCommodityTariffInstance();
51211

52212
using namespace chip::app::CommodityTariffAttrsDataMgmt;
53213
using CommodityTariffAttrTypeEnum = chip::app::Clusters::CommodityTariff::CommodityTariffDelegate::CommodityTariffAttrTypeEnum;
@@ -109,8 +269,17 @@ void SetTestEventTrigger_TariffDataUpdated()
109269
if (err != CHIP_NO_ERROR)
110270
return;
111271

112-
instance->ActivateTariffTimeTracking(tariff_preset.TariffTestTimestamp);
113-
dg->TariffDataUpdate(tariff_preset.TariffTestTimestamp);
272+
// Enable test time with the preset timestamp
273+
gTestTimeManager.EnableTestTime(true, tariff_preset.TariffTestTimestamp);
274+
275+
if (dg)
276+
{
277+
dg->TariffDataUpdate(tariff_preset.TariffTestTimestamp);
278+
}
279+
else
280+
{
281+
ChipLogError(AppServer, "The tariff provider instance is null");
282+
}
114283
}
115284

116285
void SetTestEventTrigger_TariffDataClear()
@@ -126,13 +295,8 @@ void SetTestEventTrigger_TariffDataClear()
126295
*/
127296
void SetTestEventTrigger_TimeShift24h()
128297
{
129-
CommodityTariffInstance * instance = GetCommodityTariffInstance();
130-
131-
if (instance)
132-
{
133-
instance->TariffTimeTrackingSetOffset(kSecondsPerDay);
134-
instance->TariffTimeAttrsSync();
135-
}
298+
gTestTimeManager.EnableTestTime(true);
299+
gTestTimeManager.AdvanceTestTime(chip::System::Clock::Seconds32(kSecondsPerDay));
136300
}
137301

138302
/*
@@ -141,23 +305,13 @@ void SetTestEventTrigger_TimeShift24h()
141305
*/
142306
void SetTestEventTrigger_TimeShift4h()
143307
{
144-
CommodityTariffInstance * instance = GetCommodityTariffInstance();
145-
146-
if (instance)
147-
{
148-
instance->TariffTimeTrackingSetOffset(kSecondsPer4hr);
149-
instance->TariffTimeAttrsSync();
150-
}
308+
gTestTimeManager.EnableTestTime(true);
309+
gTestTimeManager.AdvanceTestTime(chip::System::Clock::Seconds32(kSecondsPer4hr));
151310
}
152311

153312
void SetTestEventTrigger_TimeShiftDisable()
154313
{
155-
CommodityTariffInstance * instance = GetCommodityTariffInstance();
156-
157-
if (instance)
158-
{
159-
instance->TariffTimeTrackingSetOffset(0);
160-
}
314+
gTestTimeManager.EnableTestTime(false);
161315
}
162316

163317
bool HandleCommodityTariffTestEventTrigger(uint64_t eventTrigger)

examples/energy-gateway-app/commodity-tariff/src/CommodityTariffInstance.cpp

Lines changed: 24 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@
1818

1919
#include <CommodityTariffInstance.h>
2020
#include <cinttypes>
21-
#include <cstdint>
22-
#include <unordered_set>
2321

2422
using namespace chip;
2523
using namespace chip::app;
@@ -32,6 +30,9 @@ using namespace chip::app::Clusters::CommodityTariff::Attributes;
3230
using namespace chip::app::Clusters::CommodityTariff::Structs;
3331
using namespace chip::app::CommodityTariffAttrsDataMgmt;
3432
using namespace CommodityTariffConsts;
33+
using namespace chip::System;
34+
using namespace chip::System::Clock;
35+
using namespace chip::System::Clock::Literals;
3536

3637
using chip::Protocols::InteractionModel::Status;
3738

@@ -43,51 +44,47 @@ using DayStructType = DayStruct::Type;
4344
using DayPatternStructType = DayPatternStruct::Type;
4445
using CalendarPeriodStructType = CalendarPeriodStruct::Type;
4546

46-
CHIP_ERROR CommodityTariffInstance::Init()
47-
{
48-
return Instance::Init();
49-
}
47+
// ============================================================================
48+
// Existing Tariff Implementation
49+
// ============================================================================
5050

51-
uint32_t CommodityTariffInstance::GetCurrentTimestamp()
51+
void CommodityTariffInstance::ScheduleTariffTimeUpdate()
5252
{
53-
return TimestampNow + TestTimeOverlay;
53+
constexpr auto pollInterval = kTimerPollIntervalInSec * 1_s;
54+
55+
DeviceLayer::SystemLayer().StartTimer(
56+
pollInterval, [](System::Layer *, void * context) { static_cast<CommodityTariffInstance *>(context)->TariffTimeUpdCb(); },
57+
this);
5458
}
5559

56-
void CommodityTariffInstance::ScheduleTariffTimeUpdate()
60+
void CommodityTariffInstance::CancelTariffTimeUpdate()
5761
{
58-
DeviceLayer::SystemLayer().StartTimer(
59-
System::Clock::Milliseconds32(kTimerPollIntervalInSec * 1000),
62+
DeviceLayer::SystemLayer().CancelTimer(
6063
[](System::Layer *, void * context) { static_cast<CommodityTariffInstance *>(context)->TariffTimeUpdCb(); }, this);
6164
}
6265

6366
void CommodityTariffInstance::TariffTimeUpdCb()
6467
{
65-
GetDelegate()->TryToactivateDelayedTariff(TimestampNow);
66-
TimestampNow += kTimerPollIntervalInSec;
67-
TariffTimeAttrsSync();
68-
ScheduleTariffTimeUpdate();
69-
}
68+
uint32_t currentTimestamp = 0;
7069

71-
void CommodityTariffInstance::ActivateTariffTimeTracking(uint32_t timestamp)
72-
{
73-
TimestampNow = timestamp;
70+
if (CHIP_NO_ERROR == GetClock_MatterEpochS(currentTimestamp))
71+
{
72+
GetDelegate()->TryToactivateDelayedTariff(currentTimestamp);
73+
}
7474

75+
TariffTimeAttrsSync();
7576
ScheduleTariffTimeUpdate();
7677
}
7778

78-
void CommodityTariffInstance::TariffTimeTrackingSetOffset(uint32_t offset)
79+
CHIP_ERROR CommodityTariffInstance::Init()
7980
{
80-
if (offset)
81-
{
82-
TestTimeOverlay += offset;
83-
return;
84-
}
85-
86-
TestTimeOverlay = 0;
81+
ScheduleTariffTimeUpdate();
82+
return Instance::Init();
8783
}
8884

8985
void CommodityTariffInstance::Shutdown()
9086
{
87+
CancelTariffTimeUpdate();
9188
Instance::Shutdown();
9289
}
9390

0 commit comments

Comments
 (0)