feat(matter): adds matter occupancy sensor endpoint
This commit is contained in:
parent
59d51de642
commit
e17900b02a
7 changed files with 322 additions and 0 deletions
|
|
@ -179,6 +179,7 @@ set(ARDUINO_LIBRARY_Matter_SRCS
|
||||||
libraries/Matter/src/MatterEndpoints/MatterHumiditySensor.cpp
|
libraries/Matter/src/MatterEndpoints/MatterHumiditySensor.cpp
|
||||||
libraries/Matter/src/MatterEndpoints/MatterContactSensor.cpp
|
libraries/Matter/src/MatterEndpoints/MatterContactSensor.cpp
|
||||||
libraries/Matter/src/MatterEndpoints/MatterPressureSensor.cpp
|
libraries/Matter/src/MatterEndpoints/MatterPressureSensor.cpp
|
||||||
|
libraries/Matter/src/MatterEndpoints/MatterOccupancySensor.cpp
|
||||||
libraries/Matter/src/Matter.cpp)
|
libraries/Matter/src/Matter.cpp)
|
||||||
|
|
||||||
set(ARDUINO_LIBRARY_PPP_SRCS
|
set(ARDUINO_LIBRARY_PPP_SRCS
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,129 @@
|
||||||
|
// Copyright 2024 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This example is an example code that will create a Matter Device which can be
|
||||||
|
* commissioned and controlled from a Matter Environment APP.
|
||||||
|
* Additionally the ESP32 will send debug messages indicating the Matter activity.
|
||||||
|
* Turning DEBUG Level ON may be useful to following Matter Accessory and Controller messages.
|
||||||
|
*
|
||||||
|
* The example will create a Matter Occupancy Sensor Device.
|
||||||
|
* The Occupancy Sensor will be simulated to change its state every 2 minutes.
|
||||||
|
*
|
||||||
|
* The onboard button can be kept pressed for 5 seconds to decommission the Matter Node.
|
||||||
|
* The example will also show the manual commissioning code and QR code to be used in the Matter environment.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Matter Manager
|
||||||
|
#include <Matter.h>
|
||||||
|
#include <WiFi.h>
|
||||||
|
|
||||||
|
// List of Matter Endpoints for this Node
|
||||||
|
// Matter Occupancy Sensor Endpoint
|
||||||
|
MatterOccupancySensor OccupancySensor;
|
||||||
|
|
||||||
|
// set your board USER BUTTON pin here - decommissioning only
|
||||||
|
const uint8_t buttonPin = BOOT_PIN; // Set your pin here. Using BOOT Button.
|
||||||
|
|
||||||
|
// WiFi is manually set and started
|
||||||
|
const char *ssid = "your-ssid"; // Change this to your WiFi SSID
|
||||||
|
const char *password = "your-password"; // Change this to your WiFi password
|
||||||
|
|
||||||
|
// Button control
|
||||||
|
uint32_t button_time_stamp = 0; // debouncing control
|
||||||
|
bool button_state = false; // false = released | true = pressed
|
||||||
|
const uint32_t decommissioningTimeout = 5000; // keep the button pressed for 5s, or longer, to decommission
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
// Initialize the USER BUTTON (Boot button) that will be used to decommission the Matter Node
|
||||||
|
// The button will also be used to manually toggle the Occupancy Sensor state
|
||||||
|
pinMode(buttonPin, INPUT_PULLUP);
|
||||||
|
|
||||||
|
Serial.begin(115200);
|
||||||
|
|
||||||
|
// Manually connect to WiFi
|
||||||
|
WiFi.begin(ssid, password);
|
||||||
|
// Wait for connection
|
||||||
|
while (WiFi.status() != WL_CONNECTED) {
|
||||||
|
delay(500);
|
||||||
|
Serial.print(".");
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
|
||||||
|
// set initial occupancy sensor state as false and connected to a PIR sensor type (default)
|
||||||
|
OccupancySensor.begin();
|
||||||
|
|
||||||
|
// Matter beginning - Last step, after all EndPoints are initialized
|
||||||
|
Matter.begin();
|
||||||
|
|
||||||
|
// Check Matter Accessory Commissioning state, which may change during execution of loop()
|
||||||
|
if (!Matter.isDeviceCommissioned()) {
|
||||||
|
Serial.println("");
|
||||||
|
Serial.println("Matter Node is not commissioned yet.");
|
||||||
|
Serial.println("Initiate the device discovery in your Matter environment.");
|
||||||
|
Serial.println("Commission it to your Matter hub with the manual pairing code or QR code");
|
||||||
|
Serial.printf("Manual pairing code: %s\r\n", Matter.getManualPairingCode().c_str());
|
||||||
|
Serial.printf("QR code URL: %s\r\n", Matter.getOnboardingQRCodeUrl().c_str());
|
||||||
|
// waits for Matter Occupancy Sensor Commissioning.
|
||||||
|
uint32_t timeCount = 0;
|
||||||
|
while (!Matter.isDeviceCommissioned()) {
|
||||||
|
delay(100);
|
||||||
|
if ((timeCount++ % 50) == 0) { // 50*100ms = 5 sec
|
||||||
|
Serial.println("Matter Node not commissioned yet. Waiting for commissioning.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Serial.println("Matter Node is commissioned and connected to Wi-Fi. Ready for use.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool simulatedHWOccupancySensor() {
|
||||||
|
// Simulated Occupancy Sensor
|
||||||
|
static bool occupancyState = false;
|
||||||
|
static uint32_t lastTime = millis();
|
||||||
|
const uint32_t occupancyTimeout = 120000; // 2 minutes to toggle the state
|
||||||
|
|
||||||
|
// Simulate a Occupancy Sensor state change every 2 minutes
|
||||||
|
if (millis() - lastTime > occupancyTimeout) {
|
||||||
|
occupancyState = !occupancyState;
|
||||||
|
lastTime = millis();
|
||||||
|
}
|
||||||
|
return occupancyState;
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
// Check if the button has been pressed
|
||||||
|
if (digitalRead(buttonPin) == LOW && !button_state) {
|
||||||
|
// deals with button debouncing
|
||||||
|
button_time_stamp = millis(); // record the time while the button is pressed.
|
||||||
|
button_state = true; // pressed.
|
||||||
|
}
|
||||||
|
|
||||||
|
if (button_state && digitalRead(buttonPin) == HIGH) {
|
||||||
|
button_state = false; // released
|
||||||
|
}
|
||||||
|
|
||||||
|
// Onboard User Button is kept pressed for longer than 5 seconds in order to decommission matter node
|
||||||
|
uint32_t time_diff = millis() - button_time_stamp;
|
||||||
|
if (button_state && time_diff > decommissioningTimeout) {
|
||||||
|
Serial.println("Decommissioning the Generic Switch Matter Accessory. It shall be commissioned again.");
|
||||||
|
Matter.decommission();
|
||||||
|
button_time_stamp = millis(); // avoid running decommissining again, reboot takes a second or so
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check Simulated Occupancy Sensor and set Matter Attribute
|
||||||
|
OccupancySensor.setOccupancy(simulatedHWOccupancySensor());
|
||||||
|
|
||||||
|
delay(50);
|
||||||
|
}
|
||||||
7
libraries/Matter/examples/MatterOccupancySensor/ci.json
Normal file
7
libraries/Matter/examples/MatterOccupancySensor/ci.json
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"fqbn_append": "PartitionScheme=huge_app",
|
||||||
|
"requires": [
|
||||||
|
"CONFIG_SOC_WIFI_SUPPORTED=y",
|
||||||
|
"CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -22,6 +22,7 @@ MatterTemperatureSensor KEYWORD1
|
||||||
MatterHumiditySensor KEYWORD1
|
MatterHumiditySensor KEYWORD1
|
||||||
MatterContactSensor KEYWORD1
|
MatterContactSensor KEYWORD1
|
||||||
MatterPressureSensor KEYWORD1
|
MatterPressureSensor KEYWORD1
|
||||||
|
MatterOccupancySensor KEYWORD1
|
||||||
|
|
||||||
#######################################
|
#######################################
|
||||||
# Methods and Functions (KEYWORD2)
|
# Methods and Functions (KEYWORD2)
|
||||||
|
|
@ -74,6 +75,8 @@ setContact KEYWORD2
|
||||||
getContact KEYWORD2
|
getContact KEYWORD2
|
||||||
setPressure KEYWORD2
|
setPressure KEYWORD2
|
||||||
getPressure KEYWORD2
|
getPressure KEYWORD2
|
||||||
|
setOccupancy KEYWORD2
|
||||||
|
getOccupancy KEYWORD2
|
||||||
|
|
||||||
#######################################
|
#######################################
|
||||||
# Constants (LITERAL1)
|
# Constants (LITERAL1)
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@
|
||||||
#include <MatterEndpoints/MatterHumiditySensor.h>
|
#include <MatterEndpoints/MatterHumiditySensor.h>
|
||||||
#include <MatterEndpoints/MatterContactSensor.h>
|
#include <MatterEndpoints/MatterContactSensor.h>
|
||||||
#include <MatterEndpoints/MatterPressureSensor.h>
|
#include <MatterEndpoints/MatterPressureSensor.h>
|
||||||
|
#include <MatterEndpoints/MatterOccupancySensor.h>
|
||||||
|
|
||||||
using namespace esp_matter;
|
using namespace esp_matter;
|
||||||
|
|
||||||
|
|
@ -66,6 +67,7 @@ public:
|
||||||
friend class MatterHumiditySensor;
|
friend class MatterHumiditySensor;
|
||||||
friend class MatterContactSensor;
|
friend class MatterContactSensor;
|
||||||
friend class MatterPressureSensor;
|
friend class MatterPressureSensor;
|
||||||
|
friend class MatterOccupancySensor;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static void _init();
|
static void _init();
|
||||||
|
|
|
||||||
107
libraries/Matter/src/MatterEndpoints/MatterOccupancySensor.cpp
Normal file
107
libraries/Matter/src/MatterEndpoints/MatterOccupancySensor.cpp
Normal file
|
|
@ -0,0 +1,107 @@
|
||||||
|
// Copyright 2024 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include <sdkconfig.h>
|
||||||
|
#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL
|
||||||
|
|
||||||
|
#include <Matter.h>
|
||||||
|
#include <app/server/Server.h>
|
||||||
|
#include <MatterEndpoints/MatterOccupancySensor.h>
|
||||||
|
|
||||||
|
using namespace esp_matter;
|
||||||
|
using namespace esp_matter::endpoint;
|
||||||
|
using namespace chip::app::Clusters;
|
||||||
|
|
||||||
|
const uint8_t MatterOccupancySensor::occupancySensorTypeBitmap[4] = {
|
||||||
|
MatterOccupancySensor::occupancySensorTypePir,
|
||||||
|
MatterOccupancySensor::occupancySensorTypePir | MatterOccupancySensor::occupancySensorTypeUltrasonic,
|
||||||
|
MatterOccupancySensor::occupancySensorTypeUltrasonic,
|
||||||
|
MatterOccupancySensor::occupancySensorTypePhysicalContact
|
||||||
|
};
|
||||||
|
|
||||||
|
bool MatterOccupancySensor::attributeChangeCB(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val) {
|
||||||
|
bool ret = true;
|
||||||
|
if (!started) {
|
||||||
|
log_e("Matter Occupancy Sensor device has not begun.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_d("Occupancy Sensor Attr update callback: endpoint: %u, cluster: %u, attribute: %u, val: %u", endpoint_id, cluster_id, attribute_id, val->val.u32);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
MatterOccupancySensor::MatterOccupancySensor() {}
|
||||||
|
|
||||||
|
MatterOccupancySensor::~MatterOccupancySensor() {
|
||||||
|
end();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MatterOccupancySensor::begin(bool _occupancyState, OccupancySensorType_t _occupancySensorType) {
|
||||||
|
ArduinoMatter::_init();
|
||||||
|
|
||||||
|
occupancy_sensor::config_t occupancy_sensor_config;
|
||||||
|
occupancy_sensor_config.occupancy_sensing.occupancy = _occupancyState;
|
||||||
|
occupancy_sensor_config.occupancy_sensing.occupancy_sensor_type = _occupancySensorType;
|
||||||
|
occupancy_sensor_config.occupancy_sensing.occupancy_sensor_type_bitmap = occupancySensorTypeBitmap[_occupancySensorType];
|
||||||
|
|
||||||
|
// endpoint handles can be used to add/modify clusters.
|
||||||
|
endpoint_t *endpoint = occupancy_sensor::create(node::get(), &occupancy_sensor_config, ENDPOINT_FLAG_NONE, (void *)this);
|
||||||
|
if (endpoint == nullptr) {
|
||||||
|
log_e("Failed to create Occupancy Sensor endpoint");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
occupancyState = _occupancyState;
|
||||||
|
setEndPointId(endpoint::get_id(endpoint));
|
||||||
|
log_i("Occupancy Sensor created with endpoint_id %d", getEndPointId());
|
||||||
|
started = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MatterOccupancySensor::end() {
|
||||||
|
started = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MatterOccupancySensor::setOccupancy(bool _occupancyState) {
|
||||||
|
if (!started) {
|
||||||
|
log_e("Matter Occupancy Sensor device has not begun.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// avoid processing the a "no-change"
|
||||||
|
if (occupancyState == _occupancyState) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_matter_attr_val_t occupancyVal = esp_matter_invalid(NULL);
|
||||||
|
|
||||||
|
if (!getAttributeVal(OccupancySensing::Id, OccupancySensing::Attributes::Occupancy::Id, &occupancyVal)) {
|
||||||
|
log_e("Failed to get Occupancy Sensor Attribute.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (occupancyVal.val.u8 != _occupancyState) {
|
||||||
|
occupancyVal.val.u8 = _occupancyState;
|
||||||
|
bool ret;
|
||||||
|
ret = updateAttributeVal(OccupancySensing::Id, OccupancySensing::Attributes::Occupancy::Id, &occupancyVal);
|
||||||
|
if (!ret) {
|
||||||
|
log_e("Failed to update Occupancy Sensor Attribute.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
occupancyState = _occupancyState;
|
||||||
|
}
|
||||||
|
log_v("Occupancy Sensor set to %s", _occupancyState ? "Occupied" : "Vacant");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */
|
||||||
73
libraries/Matter/src/MatterEndpoints/MatterOccupancySensor.h
Normal file
73
libraries/Matter/src/MatterEndpoints/MatterOccupancySensor.h
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
// Copyright 2024 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <sdkconfig.h>
|
||||||
|
#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL
|
||||||
|
|
||||||
|
#include <Matter.h>
|
||||||
|
#include <MatterEndPoint.h>
|
||||||
|
#include <app-common/zap-generated/cluster-objects.h>
|
||||||
|
|
||||||
|
using namespace chip::app::Clusters::OccupancySensing;
|
||||||
|
|
||||||
|
class MatterOccupancySensor : public MatterEndPoint {
|
||||||
|
public:
|
||||||
|
// Different Occupancy Sensor Types
|
||||||
|
enum OccupancySensorType_t {
|
||||||
|
OCCUPANCY_SENSOR_TYPE_PIR = (uint8_t)OccupancySensorTypeEnum::kPir,
|
||||||
|
OCCUPANCY_SENSOR_TYPE_ULTRASONIC = (uint8_t)OccupancySensorTypeEnum::kUltrasonic,
|
||||||
|
OCCUPANCY_SENSOR_TYPE_PIR_AND_ULTRASONIC = (uint8_t)OccupancySensorTypeEnum::kPIRAndUltrasonic,
|
||||||
|
OCCUPANCY_SENSOR_TYPE_PHYSICAL_CONTACT = (uint8_t)OccupancySensorTypeEnum::kPhysicalContact
|
||||||
|
};
|
||||||
|
|
||||||
|
MatterOccupancySensor();
|
||||||
|
~MatterOccupancySensor();
|
||||||
|
// begin Matter Occupancy Sensor endpoint with initial occupancy state and default PIR sensor type
|
||||||
|
bool begin(bool _occupancyState = false, OccupancySensorType_t _occupancySensorType = OCCUPANCY_SENSOR_TYPE_PIR);
|
||||||
|
// this will just stop processing Occupancy Sensor Matter events
|
||||||
|
void end();
|
||||||
|
|
||||||
|
// set the occupancy state
|
||||||
|
bool setOccupancy(bool _occupancyState);
|
||||||
|
// returns the occupancy state
|
||||||
|
bool getOccupancy() {
|
||||||
|
return occupancyState;
|
||||||
|
}
|
||||||
|
|
||||||
|
// bool conversion operator
|
||||||
|
void operator=(bool _occupancyState) {
|
||||||
|
setOccupancy(_occupancyState);
|
||||||
|
}
|
||||||
|
// bool conversion operator
|
||||||
|
operator bool() {
|
||||||
|
return getOccupancy();
|
||||||
|
}
|
||||||
|
|
||||||
|
// this function is called by Matter internal event processor. It could be overwritten by the application, if necessary.
|
||||||
|
bool attributeChangeCB(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// bitmap for Occupancy Sensor Types
|
||||||
|
static const uint8_t occupancySensorTypePir = 0x01;
|
||||||
|
static const uint8_t occupancySensorTypeUltrasonic = 0x02;
|
||||||
|
static const uint8_t occupancySensorTypePhysicalContact = 0x04;
|
||||||
|
|
||||||
|
// bitmap for Occupancy Sensor Type Bitmap mapped array
|
||||||
|
static const uint8_t occupancySensorTypeBitmap[4];
|
||||||
|
|
||||||
|
bool started = false;
|
||||||
|
bool occupancyState = false;
|
||||||
|
};
|
||||||
|
#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */
|
||||||
Loading…
Reference in a new issue