Skip to content

Commit 99d8680

Browse files
Implement Occupancy Sensor Device in All-Devices App & Refactor DeviceFactory (project-chip#42404)
* Add occupancy sensor to all devices app * fix device factory; log errors * Fix TC_OCC test run * Add all-devices-app occupancy sensor tests to CI * code review suggestions * restyle * Apply review suggestions * Address Andrei's review suggestions and remove unnecessary public_configs * restyle * remove redundant comment * move timer start/stop to register/unregister * make constant seconds16 * simplify toggling-occupancy-sensor target name
1 parent 9bb7762 commit 99d8680

File tree

18 files changed

+401
-31
lines changed

18 files changed

+401
-31
lines changed

examples/all-devices-app/all-devices-common/devices/boolean-state-sensor/BUILD.gn

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,4 @@ source_set("boolean-state-sensor") {
2929
"${chip_root}/src/lib/core:error",
3030
"${chip_root}/src/lib/support",
3131
]
32-
33-
public_configs = [
34-
"${chip_root}/examples/all-devices-app/all-devices-common/devices/:includes",
35-
"${chip_root}/src:includes",
36-
]
3732
}

examples/all-devices-app/all-devices-common/devices/device-factory/BUILD.gn

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,7 @@ source_set("device-factory") {
2020

2121
public_deps = [
2222
"${chip_root}/examples/all-devices-app/all-devices-common/devices/boolean-state-sensor",
23-
"${chip_root}/src/lib/core:error",
24-
"${chip_root}/zzz_generated/app-common/devices/",
25-
]
26-
27-
public_configs = [
28-
"${chip_root}/examples/all-devices-app/all-devices-common/devices/:includes",
29-
"${chip_root}/src:includes",
23+
"${chip_root}/examples/all-devices-app/all-devices-common/devices/occupancy-sensor/impl:toggling",
24+
"${chip_root}/src/lib/support",
3025
]
3126
}

examples/all-devices-app/all-devices-common/devices/device-factory/DeviceFactory.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include <devices/Types.h>
2121
#include <devices/boolean-state-sensor/BooleanStateSensorDevice.h>
22+
#include <devices/occupancy-sensor/impl/TogglingOccupancySensorDevice.h>
2223
#include <functional>
2324
#include <lib/core/CHIPError.h>
2425
#include <map>
@@ -77,6 +78,7 @@ class DeviceFactory
7778
return std::make_unique<BooleanStateSensorDevice>(
7879
&timer, Span<const DataModel::DeviceTypeEntry>(&Device::Type::kWaterLeakDetector, 1));
7980
};
81+
mRegistry["occupancy-sensor"] = []() { return std::make_unique<TogglingOccupancySensorDevice>(); };
8082
}
8183
};
8284

examples/all-devices-app/all-devices-common/devices/interface/BUILD.gn

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,4 @@ source_set("single-endpoint-device") {
4747
"${chip_root}/src/lib/core:error",
4848
"${chip_root}/src/lib/support",
4949
]
50-
51-
public_configs = [
52-
"${chip_root}/examples/all-devices-app/all-devices-common/devices/:includes",
53-
"${chip_root}/src:includes",
54-
]
5550
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Copyright (c) 2025 Project CHIP Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import("//build_overrides/build.gni")
16+
import("//build_overrides/chip.gni")
17+
18+
source_set("occupancy-sensor") {
19+
sources = [
20+
"OccupancySensorDevice.cpp",
21+
"OccupancySensorDevice.h",
22+
]
23+
24+
public_deps = [
25+
"${chip_root}/examples/all-devices-app/all-devices-common/devices/interface:single-endpoint-device",
26+
"${chip_root}/src/app/clusters/identify-server",
27+
"${chip_root}/src/app/clusters/occupancy-sensor-server",
28+
"${chip_root}/src/data-model-providers/codedriven",
29+
"${chip_root}/src/lib/core:error",
30+
"${chip_root}/src/lib/support",
31+
"${chip_root}/zzz_generated/app-common/devices/",
32+
]
33+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
*
3+
* Copyright (c) 2025 Project CHIP Authors
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
#include <devices/Types.h>
18+
#include <devices/occupancy-sensor/OccupancySensorDevice.h>
19+
#include <lib/support/logging/CHIPLogging.h>
20+
21+
using namespace chip::app::Clusters;
22+
23+
namespace chip {
24+
namespace app {
25+
26+
OccupancySensorDevice::OccupancySensorDevice(OccupancySensingConfig config, TimerDelegate & timerDelegate) :
27+
SingleEndpointDevice(Span<const DataModel::DeviceTypeEntry>(&Device::Type::kOccupancySensor, 1)), mConfig(config),
28+
mTimerDelegate(timerDelegate)
29+
{}
30+
31+
CHIP_ERROR OccupancySensorDevice::Register(chip::EndpointId endpoint, CodeDrivenDataModelProvider & provider, EndpointId parentId)
32+
{
33+
ReturnErrorOnFailure(SingleEndpointRegistration(endpoint, provider, parentId));
34+
35+
// Create the identify cluster.
36+
mIdentifyCluster.Create(IdentifyCluster::Config(endpoint, mTimerDelegate));
37+
ReturnErrorOnFailure(provider.AddCluster(mIdentifyCluster.Registration()));
38+
39+
// Update the config with the actual endpoint ID
40+
mConfig.mEndpointId = endpoint;
41+
42+
// Create the occupancy sensing cluster
43+
mOccupancySensingCluster.Create(mConfig);
44+
ReturnErrorOnFailure(provider.AddCluster(mOccupancySensingCluster.Registration()));
45+
46+
return provider.AddEndpoint(mEndpointRegistration);
47+
}
48+
49+
void OccupancySensorDevice::UnRegister(CodeDrivenDataModelProvider & provider)
50+
{
51+
SingleEndpointUnregistration(provider);
52+
if (mOccupancySensingCluster.IsConstructed())
53+
{
54+
LogErrorOnFailure(provider.RemoveCluster(&mOccupancySensingCluster.Cluster()));
55+
mOccupancySensingCluster.Destroy();
56+
}
57+
if (mIdentifyCluster.IsConstructed())
58+
{
59+
LogErrorOnFailure(provider.RemoveCluster(&mIdentifyCluster.Cluster()));
60+
mIdentifyCluster.Destroy();
61+
}
62+
}
63+
64+
} // namespace app
65+
} // namespace chip
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
*
3+
* Copyright (c) 2025 Project CHIP Authors
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
#pragma once
18+
19+
#include <app/clusters/identify-server/IdentifyCluster.h>
20+
#include <app/clusters/occupancy-sensor-server/OccupancySensingCluster.h>
21+
#include <devices/interface/SingleEndpointDevice.h>
22+
#include <lib/support/TimerDelegate.h>
23+
24+
namespace chip {
25+
namespace app {
26+
27+
class OccupancySensorDevice : public SingleEndpointDevice
28+
{
29+
public:
30+
using OccupancySensingConfig = Clusters::OccupancySensingCluster::Config;
31+
32+
OccupancySensorDevice(OccupancySensingConfig config, TimerDelegate & timerDelegate);
33+
~OccupancySensorDevice() override = default;
34+
35+
CHIP_ERROR Register(chip::EndpointId endpoint, CodeDrivenDataModelProvider & provider,
36+
EndpointId parentId = kInvalidEndpointId) override;
37+
void UnRegister(CodeDrivenDataModelProvider & provider) override;
38+
39+
Clusters::OccupancySensingCluster & OccupancySensingCluster() { return mOccupancySensingCluster.Cluster(); }
40+
41+
protected:
42+
OccupancySensingConfig mConfig;
43+
TimerDelegate & mTimerDelegate;
44+
LazyRegisteredServerCluster<Clusters::IdentifyCluster> mIdentifyCluster;
45+
LazyRegisteredServerCluster<Clusters::OccupancySensingCluster> mOccupancySensingCluster;
46+
};
47+
48+
} // namespace app
49+
} // namespace chip
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Copyright (c) 2025 Project CHIP Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import("//build_overrides/build.gni")
16+
import("//build_overrides/chip.gni")
17+
18+
source_set("toggling") {
19+
sources = [
20+
"TogglingOccupancySensorDevice.cpp",
21+
"TogglingOccupancySensorDevice.h",
22+
]
23+
24+
public_deps = [
25+
"${chip_root}/examples/all-devices-app/all-devices-common/devices/occupancy-sensor",
26+
"${chip_root}/src/lib/support",
27+
"${chip_root}/src/platform",
28+
]
29+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
*
3+
* Copyright (c) 2025 Project CHIP Authors
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
#include "TogglingOccupancySensorDevice.h"
18+
#include <lib/support/CodeUtils.h>
19+
#include <lib/support/logging/CHIPLogging.h>
20+
#include <platform/CHIPDeviceLayer.h>
21+
22+
using namespace chip::app::Clusters;
23+
24+
namespace chip {
25+
namespace app {
26+
27+
namespace {
28+
constexpr System::Clock::Seconds16 kOccupancyStateChangeIntervalSec = System::Clock::Seconds16(30);
29+
} // namespace
30+
31+
TogglingOccupancySensorDevice::TogglingOccupancySensorDevice() :
32+
OccupancySensorDevice(
33+
// Initialize with kInvalidEndpointId. The actual endpoint ID will be set
34+
// when Register() is called by the application with a valid endpoint ID.
35+
OccupancySensingCluster::Config(kInvalidEndpointId)
36+
.WithFeatures(OccupancySensing::Feature::kPassiveInfrared)
37+
.WithHoldTime(10,
38+
{
39+
.holdTimeMin = 1,
40+
.holdTimeMax = 300,
41+
.holdTimeDefault = 10,
42+
},
43+
mTimerDelegate)
44+
.WithDelegate(this),
45+
mTimerDelegate)
46+
{}
47+
48+
TogglingOccupancySensorDevice::~TogglingOccupancySensorDevice()
49+
{
50+
mTimerDelegate.CancelTimer(this);
51+
}
52+
53+
CHIP_ERROR TogglingOccupancySensorDevice::Register(EndpointId endpoint, CodeDrivenDataModelProvider & provider, EndpointId parentId)
54+
{
55+
ReturnErrorOnFailure(OccupancySensorDevice::Register(endpoint, provider, parentId));
56+
// Kick off the timer loop to flip occupancy every few seconds
57+
return mTimerDelegate.StartTimer(this, kOccupancyStateChangeIntervalSec);
58+
}
59+
60+
void TogglingOccupancySensorDevice::UnRegister(CodeDrivenDataModelProvider & provider)
61+
{
62+
mTimerDelegate.CancelTimer(this);
63+
OccupancySensorDevice::UnRegister(provider);
64+
}
65+
66+
void TogglingOccupancySensorDevice::OnOccupancyChanged(bool occupied)
67+
{
68+
ChipLogProgress(AppServer, "TogglingOccupancySensorDevice::OnOccupancyChanged: %s", occupied ? "Occupied" : "Unoccupied");
69+
}
70+
71+
void TogglingOccupancySensorDevice::OnHoldTimeChanged(uint16_t holdTime)
72+
{
73+
ChipLogProgress(AppServer, "TogglingOccupancySensorDevice::OnHoldTimeChanged: %u", holdTime);
74+
}
75+
76+
void TogglingOccupancySensorDevice::TimerFired()
77+
{
78+
// Flips the occupancy state every kOccupancyStateChangeIntervalSec seconds
79+
80+
bool nextState = !mOccupancySensingCluster.Cluster().IsOccupied();
81+
82+
ChipLogProgress(AppServer, "TogglingOccupancySensorDevice: Toggling occupancy to %s", nextState ? "Occupied" : "Unoccupied");
83+
mOccupancySensingCluster.Cluster().SetOccupancy(nextState);
84+
85+
VerifyOrDie(mTimerDelegate.StartTimer(this, kOccupancyStateChangeIntervalSec) == CHIP_NO_ERROR);
86+
}
87+
88+
} // namespace app
89+
} // namespace chip
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
*
3+
* Copyright (c) 2025 Project CHIP Authors
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
#pragma once
18+
19+
#include <app/clusters/occupancy-sensor-server/OccupancySensingCluster.h>
20+
#include <data-model-providers/codedriven/CodeDrivenDataModelProvider.h>
21+
#include <devices/occupancy-sensor/OccupancySensorDevice.h>
22+
#include <platform/DefaultTimerDelegate.h>
23+
24+
namespace chip {
25+
namespace app {
26+
27+
/**
28+
* @brief An implementation of an Occupancy Sensor Device.
29+
*
30+
* This class serves as a simple example of an occupancy sensor. It emulates
31+
* occupancy state changes by toggling between "Occupied" and "Unoccupied"
32+
* states every 30 seconds using a timer.
33+
*/
34+
class TogglingOccupancySensorDevice : public OccupancySensorDevice, public Clusters::OccupancySensingDelegate, public TimerContext
35+
{
36+
public:
37+
TogglingOccupancySensorDevice();
38+
~TogglingOccupancySensorDevice() override;
39+
40+
CHIP_ERROR Register(EndpointId endpoint, CodeDrivenDataModelProvider & provider,
41+
EndpointId parentId = kInvalidEndpointId) override;
42+
void UnRegister(CodeDrivenDataModelProvider & provider) override;
43+
44+
// OccupancySensingDelegate
45+
void OnOccupancyChanged(bool occupied) override;
46+
void OnHoldTimeChanged(uint16_t holdTime) override;
47+
48+
// TimerContext
49+
void TimerFired() override;
50+
51+
private:
52+
DefaultTimerDelegate mTimerDelegate;
53+
};
54+
55+
} // namespace app
56+
} // namespace chip

0 commit comments

Comments
 (0)