-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
libraries/Matter: Add MatterPowerSource.h and a battery percent repor…
…ting example
- Loading branch information
1 parent
65a739a
commit 9468c03
Showing
5 changed files
with
439 additions
and
0 deletions.
There are no files selected for viewing
146 changes: 146 additions & 0 deletions
146
libraries/Matter/examples/matter_switch_with_battery/matter_switch_with_battery.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,146 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
#include <Wire.h> | ||
#include <SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library.h> | ||
#include <Matter.h> | ||
#include <MatterSwitch.h> | ||
#include <MatterPowerSource.h> | ||
|
||
SFE_MAX1704X lipo(MAX1704X_MAX17048); | ||
uint32_t battery_gauge_timeout = 900000; // 15min | ||
void read_battery(); | ||
|
||
MatterSwitch matter_switch; | ||
MatterPowerSource matter_power_source; | ||
volatile bool button_pressed = false; | ||
void handle_button_press(); | ||
void handle_button_release(); | ||
|
||
void setup() { | ||
Serial.begin(115200); | ||
Serial.println("Matter Switch with Battery"); | ||
Wire.begin(); | ||
Matter.begin(); | ||
matter_switch.begin(); | ||
matter_power_source.begin(); | ||
|
||
// Set up the onboard button | ||
#ifndef BTN_BUILTIN | ||
#define BTN_BUILTIN PA0 | ||
#endif | ||
pinMode(BTN_BUILTIN, INPUT_PULLUP); | ||
|
||
attachInterrupt(BTN_BUILTIN, &handle_button_press, FALLING); | ||
attachInterrupt(BTN_BUILTIN, &handle_button_release, RISING); | ||
|
||
if (!Matter.isDeviceCommissioned()) { | ||
Serial.println("Matter device is not commissioned"); | ||
Serial.println("Commission it to your Matter hub with the manual pairing code or QR code"); | ||
Serial.printf("Manual pairing code: %s\n", Matter.getManualPairingCode().c_str()); | ||
Serial.printf("QR code URL: %s\n", Matter.getOnboardingQRCodeUrl().c_str()); | ||
} | ||
while (!Matter.isDeviceCommissioned()) { | ||
delay(200); | ||
} | ||
Serial.println("Matter device is commissioned"); | ||
|
||
if (!Matter.isDeviceThreadConnected()) { | ||
Serial.println("Waiting for Thread network connection..."); | ||
} | ||
while (!Matter.isDeviceThreadConnected()) { | ||
delay(200); | ||
} | ||
Serial.println("Connected to Thread network"); | ||
|
||
if (!matter_switch.is_online()) { | ||
Serial.println("Waiting for Matter switch device discovery..."); | ||
} | ||
while (!matter_switch.is_online()) { | ||
delay(200); | ||
} | ||
if (!matter_power_source.is_online()) { | ||
Serial.println("Waiting for Matter power source device discovery..."); | ||
} | ||
while (!matter_power_source.is_online()) { | ||
delay(200); | ||
} | ||
Serial.println("Matter device is now online"); | ||
|
||
if (!lipo.begin()) { | ||
Serial.println("No MAX17048 LiPo fuel gauge detected"); | ||
} else { | ||
lipo.quickStart(); | ||
lipo.setThreshold(20); | ||
read_battery(); | ||
} | ||
} | ||
|
||
void loop() { | ||
static bool button_pressed_last = false; | ||
static bool switch_state_last = false; | ||
static uint32_t battery_gauge_last = 0; | ||
|
||
// If the physical button state changes - update the switch's state | ||
if (button_pressed != button_pressed_last) { | ||
button_pressed_last = button_pressed; | ||
matter_switch.set_state(button_pressed); | ||
} | ||
|
||
// Get the current state of the Matter switch | ||
bool switch_state_current = matter_switch.get_state(); | ||
|
||
// If the current state is 'pressed' and the previous was 'not pressed' - switch pressed | ||
if (switch_state_current && !switch_state_last) { | ||
switch_state_last = switch_state_current; | ||
Serial.println("Button pressed"); | ||
read_battery(); | ||
} | ||
|
||
// If the current state is 'not pressed' and the previous was 'pressed' - switch released | ||
if (!switch_state_current && switch_state_last) { | ||
switch_state_last = switch_state_current; | ||
Serial.println("Button released"); | ||
} | ||
|
||
uint32_t time = millis(); | ||
if (time > battery_gauge_last + battery_gauge_timeout) { | ||
battery_gauge_last = time; | ||
read_battery(); | ||
} | ||
} | ||
|
||
void read_battery() { | ||
double voltage = lipo.getVoltage(); | ||
double soc = lipo.getSOC(); | ||
bool alert = lipo.getAlert(); | ||
|
||
Serial.printf("Battery Voltage: %4.2f V\n", voltage); | ||
Serial.printf("Battery Percent: %4.0f %%\n", soc); | ||
matter_power_source.set_bat_percent_remaining(soc); | ||
|
||
if (alert) { | ||
Serial.println("Battery Alert!"); | ||
} | ||
} | ||
|
||
void handle_button_press() { | ||
static uint32_t button_press_last = 0; | ||
uint32_t time = millis(); | ||
if (time < button_press_last + 200) { | ||
return; | ||
} | ||
|
||
button_press_last = time; | ||
button_pressed = true; | ||
} | ||
|
||
void handle_button_release() { | ||
static uint32_t button_press_last = 0; | ||
uint32_t time = millis(); | ||
if (time < button_press_last + 200) { | ||
return; | ||
} | ||
|
||
button_press_last = time; | ||
button_pressed = false; | ||
} |
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,140 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
#include "MatterPowerSource.h" | ||
|
||
using namespace ::chip; | ||
using namespace ::chip::Platform; | ||
using namespace ::chip::Credentials; | ||
using namespace ::chip::app::Clusters; | ||
|
||
const EmberAfDeviceType gPowerSourceDeviceTypes[] = { { DEVICE_TYPE_POWER_SOURCE, DEVICE_VERSION_DEFAULT } }; | ||
|
||
// Power source cluster attributes | ||
DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(powerSourceAttrs) | ||
DECLARE_DYNAMIC_ATTRIBUTE(PowerSource::Attributes::BatPercentRemaining::Id, INT8U, 1, 0), /* BatPercentRemaining */ | ||
DECLARE_DYNAMIC_ATTRIBUTE(PowerSource::Attributes::FeatureMap::Id, BITMAP32, 4, 0), /* FeatureMap */ | ||
DECLARE_DYNAMIC_ATTRIBUTE(PowerSource::Attributes::ClusterRevision::Id, INT16U, 2, 0), /* ClusterRevision */ | ||
DECLARE_DYNAMIC_ATTRIBUTE_LIST_END(); | ||
|
||
// Power source cluster list | ||
DECLARE_DYNAMIC_CLUSTER_LIST_BEGIN(powerSourceEndpointClusters) | ||
DECLARE_DYNAMIC_CLUSTER(PowerSource::Id, powerSourceAttrs, nullptr, nullptr), | ||
DECLARE_DYNAMIC_CLUSTER(Descriptor::Id, descriptorAttrs, nullptr, nullptr), | ||
DECLARE_DYNAMIC_CLUSTER(BridgedDeviceBasicInformation::Id, bridgedDeviceBasicAttrs, nullptr, nullptr) | ||
DECLARE_DYNAMIC_CLUSTER_LIST_END; | ||
|
||
/***************************************************************************//** | ||
* Constructor for MatterPowerSource | ||
******************************************************************************/ | ||
MatterPowerSource::MatterPowerSource() : | ||
power_source_device(nullptr), | ||
device_endpoint(nullptr), | ||
endpoint_dataversion_storage(nullptr), | ||
initialized(false) | ||
{ | ||
; | ||
} | ||
|
||
/***************************************************************************//** | ||
* Destructor for MatterPowerSource | ||
******************************************************************************/ | ||
MatterPowerSource::~MatterPowerSource() | ||
{ | ||
this->end(); | ||
} | ||
|
||
/***************************************************************************//** | ||
* Initializes the MatterPowerSource instance | ||
* | ||
* @return true if the initialization succeeded, false otherwise | ||
******************************************************************************/ | ||
bool MatterPowerSource::begin() | ||
{ | ||
if (this->initialized) { | ||
return false; | ||
} | ||
|
||
// Create new device | ||
DevicePowerSource* power_source = new (std::nothrow)DevicePowerSource("Power Source", 0); | ||
if (power_source == nullptr) { | ||
return false; | ||
} | ||
power_source->SetReachable(true); | ||
power_source->SetProductName("Power Source"); | ||
|
||
// Set the device instance pointer in the base class | ||
this->base_matter_device = power_source; | ||
|
||
// Create new endpoint | ||
EmberAfEndpointType* new_endpoint = (EmberAfEndpointType*)malloc(sizeof(EmberAfEndpointType)); | ||
if (new_endpoint == nullptr) { | ||
delete(power_source); | ||
return false; | ||
} | ||
new_endpoint->cluster = powerSourceEndpointClusters; | ||
new_endpoint->clusterCount = ArraySize(powerSourceEndpointClusters); | ||
new_endpoint->endpointSize = 0; | ||
|
||
// Create data version storage for the endpoint | ||
size_t dataversion_size = ArraySize(powerSourceEndpointClusters) * sizeof(DataVersion); | ||
DataVersion* new_power_source_data_version = (DataVersion*)malloc(dataversion_size); | ||
if (new_power_source_data_version == nullptr) { | ||
delete(power_source); | ||
free(new_endpoint); | ||
return false; | ||
} | ||
|
||
// Add new endpoint | ||
int result = AddDeviceEndpoint(power_source, | ||
new_endpoint, | ||
Span<const EmberAfDeviceType>(gPowerSourceDeviceTypes), | ||
Span<DataVersion>(new_power_source_data_version, dataversion_size), 1); | ||
if (result < 0) { | ||
delete(power_source); | ||
free(new_endpoint); | ||
free(new_power_source_data_version); | ||
return false; | ||
} | ||
|
||
this->power_source_device = power_source; | ||
this->device_endpoint = new_endpoint; | ||
this->endpoint_dataversion_storage = new_power_source_data_version; | ||
this->initialized = true; | ||
return true; | ||
} | ||
|
||
/***************************************************************************//** | ||
* Deinitializes the MatterPowerSource instance | ||
******************************************************************************/ | ||
void MatterPowerSource::end() | ||
{ | ||
if (!this->initialized) { | ||
return; | ||
} | ||
(void)RemoveDeviceEndpoint(this->power_source_device); | ||
free(this->device_endpoint); | ||
free(this->endpoint_dataversion_storage); | ||
delete(this->power_source_device); | ||
this->initialized = false; | ||
} | ||
|
||
void MatterPowerSource::set_bat_percent_remaining_raw(uint8_t value) | ||
{ | ||
if (!this->initialized) { | ||
return; | ||
} | ||
PlatformMgr().LockChipStack(); | ||
this->power_source_device->SetBatPercentRemaining(value); | ||
PlatformMgr().UnlockChipStack(); | ||
} | ||
|
||
void MatterPowerSource::set_bat_percent_remaining(double percent) | ||
{ | ||
uint8_t out_value = static_cast<uint8_t>(percent * 2.0l); | ||
this->set_bat_percent_remaining_raw(out_value); | ||
} | ||
|
||
uint8_t MatterPowerSource::get_bat_percent_remaining() | ||
{ | ||
return this->power_source_device->GetBatPercentRemaining(); | ||
} |
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,32 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
#ifndef MATTER_POWER_SOURCE_H | ||
#define MATTER_POWER_SOURCE_H | ||
|
||
#include "Matter.h" | ||
#include "devices/DevicePowerSource.h" | ||
#include <platform/CHIPDeviceLayer.h> | ||
#include <app-common/zap-generated/attributes/Accessors.h> | ||
|
||
using namespace chip; | ||
using namespace ::chip::DeviceLayer; | ||
|
||
class MatterPowerSource : public ArduinoMatterAppliance { | ||
public: | ||
MatterPowerSource(); | ||
~MatterPowerSource(); | ||
bool begin(); | ||
void end(); | ||
void set_bat_percent_remaining_raw(uint8_t value); | ||
void set_bat_percent_remaining(double percent); | ||
uint8_t get_bat_percent_remaining(); | ||
void operator=(uint8_t value); | ||
|
||
private: | ||
DevicePowerSource* power_source_device; | ||
EmberAfEndpointType* device_endpoint; | ||
DataVersion* endpoint_dataversion_storage; | ||
bool initialized; | ||
}; | ||
|
||
#endif // MATTER_POWER_SOURCE_H |
Oops, something went wrong.