-
Notifications
You must be signed in to change notification settings - Fork 7.5k
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
feat(matter): adds a new endpoint to Matter - On/Off Plugin (Power Relay) #10722
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
e17900b
feat(matter): adds matter occupancy sensor endpoint
SuGlider 3bf8f23
fix(matter): removed commentary that has no code related
SuGlider 4cf0f20
ci(pre-commit): Apply automatic fixes
pre-commit-ci-lite[bot] c310c1a
feat(matter): adds matter on off plugin endpoint
SuGlider c126f01
Merge branch 'release/v3.1.x' into matter_plugin
SuGlider faed832
ci(pre-commit): Apply automatic fixes
pre-commit-ci-lite[bot] File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
142 changes: 142 additions & 0 deletions
142
libraries/Matter/examples/MatterOnOffPlugin/MatterOnOffPlugin.ino
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
// 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. | ||
|
||
// Matter Manager | ||
#include <Matter.h> | ||
#include <WiFi.h> | ||
#include <Preferences.h> | ||
|
||
// List of Matter Endpoints for this Node | ||
// On/Off Plugin Endpoint | ||
MatterOnOffPlugin OnOffPlugin; | ||
|
||
// it will keep last OnOff state stored, using Preferences | ||
Preferences matterPref; | ||
const char *onOffPrefKey = "OnOff"; | ||
|
||
// set your board Power Relay pin here - this example uses the built-in LED for easy visualization | ||
#ifdef LED_BUILTIN | ||
const uint8_t onoffPin = LED_BUILTIN; | ||
#else | ||
const uint8_t onoffPin = 2; // Set your pin here - usually a power relay | ||
#warning "Do not forget to set the Power Relay pin" | ||
#endif | ||
|
||
// board USER BUTTON pin necessary for Decommissioning | ||
const uint8_t buttonPin = BOOT_PIN; // Set your pin here. Using BOOT Button. | ||
|
||
// 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 | ||
|
||
// 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 | ||
|
||
// Matter Protocol Endpoint Callback | ||
bool setPluginOnOff(bool state) { | ||
Serial.printf("User Callback :: New Plugin State = %s\r\n", state ? "ON" : "OFF"); | ||
if (state) { | ||
digitalWrite(onoffPin, HIGH); | ||
} else { | ||
digitalWrite(onoffPin, LOW); | ||
} | ||
// store last OnOff state for when the Plugin is restarted / power goes off | ||
matterPref.putBool(onOffPrefKey, state); | ||
// This callback must return the success state to Matter core | ||
return true; | ||
} | ||
|
||
void setup() { | ||
// Initialize the USER BUTTON | ||
pinMode(buttonPin, INPUT_PULLUP); | ||
// Initialize the Power Relay (plugin) GPIO | ||
pinMode(onoffPin, OUTPUT); | ||
|
||
Serial.begin(115200); | ||
|
||
// We start by connecting to a WiFi network | ||
Serial.print("Connecting to "); | ||
Serial.println(ssid); | ||
WiFi.begin(ssid, password); | ||
// Wait for connection | ||
while (WiFi.status() != WL_CONNECTED) { | ||
delay(500); | ||
Serial.print("."); | ||
} | ||
Serial.println("\r\nWiFi connected"); | ||
Serial.println("IP address: "); | ||
Serial.println(WiFi.localIP()); | ||
delay(500); | ||
|
||
// Initialize Matter EndPoint | ||
matterPref.begin("MatterPrefs", false); | ||
bool lastOnOffState = matterPref.getBool(onOffPrefKey, false); | ||
OnOffPlugin.begin(lastOnOffState); | ||
OnOffPlugin.onChange(setPluginOnOff); | ||
|
||
// Matter beginning - Last step, after all EndPoints are initialized | ||
Matter.begin(); | ||
// This may be a restart of a already commissioned Matter accessory | ||
if (Matter.isDeviceCommissioned()) { | ||
Serial.println("Matter Node is commissioned and connected to Wi-Fi. Ready for use."); | ||
Serial.printf("Initial state: %s\r\n", OnOffPlugin.getOnOff() ? "ON" : "OFF"); | ||
OnOffPlugin.updateAccessory(); // configure the Plugin based on initial state | ||
} | ||
} | ||
|
||
void loop() { | ||
// Check Matter Plugin 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 Plugin 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.printf("Initial state: %s\r\n", OnOffPlugin.getOnOff() ? "ON" : "OFF"); | ||
OnOffPlugin.updateAccessory(); // configure the Plugin based on initial state | ||
Serial.println("Matter Node is commissioned and connected to Wi-Fi. Ready for use."); | ||
} | ||
|
||
// 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. | ||
} | ||
|
||
// Onboard User Button is used to decommission the Matter Node | ||
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 Plugin Matter Accessory. It shall be commissioned again."); | ||
OnOffPlugin.setOnOff(false); // turn the plugin off | ||
Matter.decommission(); | ||
button_time_stamp = millis(); // avoid running decommissining again, reboot takes a second or so | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"fqbn_append": "PartitionScheme=huge_app", | ||
"requires": [ | ||
"CONFIG_SOC_WIFI_SUPPORTED=y", | ||
"CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
136 changes: 136 additions & 0 deletions
136
libraries/Matter/src/MatterEndpoints/MatterOnOffPlugin.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
// 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/MatterOnOffPlugin.h> | ||
|
||
using namespace esp_matter; | ||
using namespace esp_matter::endpoint; | ||
using namespace chip::app::Clusters; | ||
|
||
bool MatterOnOffPlugin::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 On-Off Plugin device has not begun."); | ||
return false; | ||
} | ||
|
||
log_d("OnOff Attr update callback: endpoint: %u, cluster: %u, attribute: %u, val: %u", endpoint_id, cluster_id, attribute_id, val->val.u32); | ||
|
||
if (endpoint_id == getEndPointId()) { | ||
log_d("OnOffPlugin state changed to %d", val->val.b); | ||
if (cluster_id == OnOff::Id) { | ||
if (attribute_id == OnOff::Attributes::OnOff::Id) { | ||
if (_onChangeOnOffCB != NULL) { | ||
ret &= _onChangeOnOffCB(val->val.b); | ||
} | ||
if (_onChangeCB != NULL) { | ||
ret &= _onChangeCB(val->val.b); | ||
} | ||
if (ret == true) { | ||
onOffState = val->val.b; | ||
} | ||
} | ||
} | ||
} | ||
return ret; | ||
} | ||
|
||
MatterOnOffPlugin::MatterOnOffPlugin() {} | ||
|
||
MatterOnOffPlugin::~MatterOnOffPlugin() { | ||
end(); | ||
} | ||
|
||
bool MatterOnOffPlugin::begin(bool initialState) { | ||
ArduinoMatter::_init(); | ||
on_off_plugin_unit::config_t plugin_config; | ||
|
||
plugin_config.on_off.on_off = initialState; | ||
plugin_config.on_off.lighting.start_up_on_off = nullptr; | ||
|
||
// endpoint handles can be used to add/modify clusters. | ||
endpoint_t *endpoint = on_off_plugin_unit::create(node::get(), &plugin_config, ENDPOINT_FLAG_NONE, (void *)this); | ||
if (endpoint == nullptr) { | ||
log_e("Failed to create on-off plugin endpoint"); | ||
return false; | ||
} | ||
onOffState = initialState; | ||
setEndPointId(endpoint::get_id(endpoint)); | ||
log_i("On-Off Plugin created with endpoint_id %d", getEndPointId()); | ||
started = true; | ||
return true; | ||
} | ||
|
||
void MatterOnOffPlugin::end() { | ||
started = false; | ||
} | ||
|
||
void MatterOnOffPlugin::updateAccessory() { | ||
if (_onChangeCB != NULL) { | ||
_onChangeCB(onOffState); | ||
} | ||
} | ||
|
||
bool MatterOnOffPlugin::setOnOff(bool newState) { | ||
if (!started) { | ||
log_e("Matter On-Off Plugin device has not begun."); | ||
return false; | ||
} | ||
|
||
// avoid processing the a "no-change" | ||
if (onOffState == newState) { | ||
return true; | ||
} | ||
|
||
esp_matter_attr_val_t onoffVal = esp_matter_invalid(NULL); | ||
|
||
if (!getAttributeVal(OnOff::Id, OnOff::Attributes::OnOff::Id, &onoffVal)) { | ||
log_e("Failed to get Pressure Sensor Attribute."); | ||
return false; | ||
} | ||
if (onoffVal.val.b != newState) { | ||
onoffVal.val.b = newState; | ||
bool ret; | ||
ret = updateAttributeVal(OnOff::Id, OnOff::Attributes::OnOff::Id, &onoffVal); | ||
if (!ret) { | ||
log_e("Failed to update Pressure Sensor Measurement Attribute."); | ||
return false; | ||
} | ||
onOffState = newState; | ||
} | ||
log_v("Plugin OnOff state set to %s", newState ? "ON" : "OFF"); | ||
return true; | ||
} | ||
|
||
bool MatterOnOffPlugin::getOnOff() { | ||
return onOffState; | ||
} | ||
|
||
bool MatterOnOffPlugin::toggle() { | ||
return setOnOff(!onOffState); | ||
} | ||
|
||
MatterOnOffPlugin::operator bool() { | ||
return getOnOff(); | ||
} | ||
|
||
void MatterOnOffPlugin::operator=(bool newState) { | ||
setOnOff(newState); | ||
} | ||
#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
// 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> | ||
|
||
class MatterOnOffPlugin : public MatterEndPoint { | ||
public: | ||
MatterOnOffPlugin(); | ||
~MatterOnOffPlugin(); | ||
virtual bool begin(bool initialState = false); // default initial state is off | ||
void end(); // this will just stop processing Plugin Matter events | ||
|
||
bool setOnOff(bool newState); // returns true if successful | ||
bool getOnOff(); // returns current plugin state | ||
bool toggle(); // returns true if successful | ||
|
||
// used to update the state of the plugin using the current Matter Plugin internal state | ||
// It is necessary to set a user callback function using onChange() to handle the physical plugin state | ||
void updateAccessory(); | ||
|
||
operator bool(); // returns current plugin state | ||
void operator=(bool state); // turns plugin on or off | ||
// 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); | ||
// User Callback for whenever the Plugin state is changed by the Matter Controller | ||
using EndPointCB = std::function<bool(bool)>; | ||
void onChange(EndPointCB onChangeCB) { | ||
_onChangeCB = onChangeCB; | ||
} | ||
void onChangeOnOff(EndPointCB onChangeCB) { | ||
_onChangeOnOffCB = onChangeCB; | ||
} | ||
|
||
protected: | ||
bool started = false; | ||
bool onOffState = false; // default initial state is off, but it can be changed by begin(bool) | ||
EndPointCB _onChangeCB = NULL; | ||
EndPointCB _onChangeOnOffCB = NULL; | ||
}; | ||
#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll review this and other necessary changed at once latter on.