blob: 6f35995a4451106c873c4398a5ea7bc83b034f9f [file] [log] [blame]
/*
*
* Copyright (c) 2022 Project CHIP Authors
* All rights reserved.
*
* 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 "DeviceWithDisplay.h"
#include <app-common/zap-generated/attributes/Accessors.h>
#include <app-common/zap-generated/cluster-enums.h>
#include <app-common/zap-generated/ids/Clusters.h>
#include <setup_payload/QRCodeSetupPayloadGenerator.h>
#include <string>
#include <tuple>
#include <vector>
#if CONFIG_HAVE_DISPLAY
using namespace ::chip;
using namespace ::chip::Credentials;
using namespace ::chip::DeviceManager;
using namespace ::chip::DeviceLayer;
static const char TAG[] = "DeviceWithDisplay";
#if CONFIG_DEVICE_TYPE_M5STACK
Button gButtons[BUTTON_NUMBER] = { Button(BUTTON_1_GPIO_NUM), Button(BUTTON_2_GPIO_NUM), Button(BUTTON_3_GPIO_NUM) };
// Pretend these are devices with endpoints with clusters with attributes
typedef std::tuple<std::string, std::string> Attribute;
typedef std::vector<Attribute> Attributes;
typedef std::tuple<std::string, Attributes> Cluster;
typedef std::vector<Cluster> Clusters;
typedef std::tuple<std::string, Clusters> Endpoint;
typedef std::vector<Endpoint> Endpoints;
typedef std::tuple<std::string, Endpoints> Device;
typedef std::vector<Device> Devices;
Devices devices;
void AddAttribute(std::string name, std::string value)
{
Attribute attribute = std::make_tuple(std::move(name), std::move(value));
std::get<1>(std::get<1>(std::get<1>(devices.back()).back()).back()).emplace_back(std::move(attribute));
}
void AddCluster(std::string name)
{
Cluster cluster = std::make_tuple(std::move(name), std::move(Attributes()));
std::get<1>(std::get<1>(devices.back()).back()).emplace_back(std::move(cluster));
}
void AddEndpoint(std::string name)
{
Endpoint endpoint = std::make_tuple(std::move(name), std::move(Clusters()));
std::get<1>(devices.back()).emplace_back(std::move(endpoint));
}
void AddDevice(std::string name)
{
Device device = std::make_tuple(std::move(name), std::move(Endpoints()));
devices.emplace_back(std::move(device));
}
class TouchesMatterStackModel : public ListScreen::Model
{
// We could override Action() and then hope focusIndex has not changed by
// the time our queued task runs, but it's cleaner to just capture its value
// now.
struct QueuedAction
{
QueuedAction(TouchesMatterStackModel * selfArg, int iArg) : self(selfArg), i(iArg) {}
TouchesMatterStackModel * self;
int i;
};
void ItemAction(int i) final
{
auto * action = chip::Platform::New<QueuedAction>(this, i);
chip::DeviceLayer::PlatformMgr().ScheduleWork(QueuedActionHandler, reinterpret_cast<intptr_t>(action));
}
static void QueuedActionHandler(intptr_t closure)
{
auto * queuedAction = reinterpret_cast<QueuedAction *>(closure);
queuedAction->self->DoAction(queuedAction->i);
chip::Platform::Delete(queuedAction);
}
virtual void DoAction(int i) = 0;
};
class EditAttributeListModel : public TouchesMatterStackModel
{
int deviceIndex;
int endpointIndex;
int clusterIndex;
int attributeIndex;
public:
EditAttributeListModel(int deviceIndex, int endpointIndex, int clusterIndex, int attributeIndex) :
deviceIndex(deviceIndex), endpointIndex(endpointIndex), clusterIndex(clusterIndex), attributeIndex(attributeIndex)
{}
Attribute & attribute()
{
return std::get<1>(std::get<1>(std::get<1>(devices[deviceIndex])[endpointIndex])[clusterIndex])[attributeIndex];
}
bool IsBooleanAttribute()
{
auto & attribute = this->attribute();
auto & value = std::get<1>(attribute);
return value == "On" || value == "Off" || value == "Yes" || value == "No";
}
virtual std::string GetTitle()
{
auto & attribute = this->attribute();
auto & name = std::get<0>(attribute);
auto & value = std::get<1>(attribute);
char buffer[64];
snprintf(buffer, sizeof(buffer), "%s : %s", name.c_str(), value.c_str());
return buffer;
}
virtual int GetItemCount() { return IsBooleanAttribute() ? 1 : 2; }
virtual std::string GetItemText(int i)
{
if (IsBooleanAttribute())
{
return "Toggle";
}
return i == 0 ? "+" : "-";
}
// We support system modes - Off, Auto, Heat and Cool currently. This API returns true for all these modes,
// false otherwise.
bool isValidThermostatSystemMode(uint8_t systemMode)
{
chip::app::Clusters::Thermostat::SystemModeEnum mode =
static_cast<chip::app::Clusters::Thermostat::SystemModeEnum>(systemMode);
switch (mode)
{
case chip::app::Clusters::Thermostat::SystemModeEnum::kOff:
case chip::app::Clusters::Thermostat::SystemModeEnum::kAuto:
case chip::app::Clusters::Thermostat::SystemModeEnum::kCool:
case chip::app::Clusters::Thermostat::SystemModeEnum::kHeat:
return true;
default:
return false;
}
}
bool isValidThermostatRunningMode(uint8_t runningMode)
{
chip::app::Clusters::Thermostat::ThermostatRunningModeEnum mode =
static_cast<chip::app::Clusters::Thermostat::ThermostatRunningModeEnum>(runningMode);
switch (mode)
{
case chip::app::Clusters::Thermostat::ThermostatRunningModeEnum::kOff:
case chip::app::Clusters::Thermostat::ThermostatRunningModeEnum::kCool:
case chip::app::Clusters::Thermostat::ThermostatRunningModeEnum::kHeat:
return true;
default:
return false;
}
}
void DoAction(int i) override
{
auto & attribute = this->attribute();
auto & value = std::get<1>(attribute);
int n;
if (sscanf(value.c_str(), "%d", &n) == 1)
{
auto & name = std::get<0>(attribute);
ESP_LOGI(TAG, "editing attribute as integer: %d (%s)", n, i == 0 ? "+" : "-");
n += (i == 0) ? 1 : -1;
char buffer[32];
sprintf(buffer, "%d", n);
if (name == "Temperature")
{
// update the temp attribute here for hardcoded endpoint 1
chip::app::Clusters::TemperatureMeasurement::Attributes::MeasuredValue::Set(1, static_cast<int16_t>(n * 100));
}
else if (name == "Color Current Level")
{
// update the current level here for hardcoded endpoint 1
ESP_LOGI(TAG, "Brightness changed to : %d", (n * 100 / 255));
app::Clusters::LevelControl::Attributes::CurrentLevel::Set(1, n);
}
else if (name == "Current Hue")
{
// update the current hue here for hardcoded endpoint 1
ESP_LOGI(TAG, "Hue changed to : %d", n * 360 / 254);
app::Clusters::ColorControl::Attributes::CurrentHue::Set(1, n);
}
else if (name == "Current Saturation")
{
// update the current saturation here for hardcoded endpoint 1
ESP_LOGI(TAG, "Saturation changed to : %d", n * 100 / 254);
app::Clusters::ColorControl::Attributes::CurrentSaturation::Set(1, n);
}
else if (name == "Illuminance")
{
// update the current illuminance here for hardcoded endpoint 1
ESP_LOGI(TAG, "Illuminance changed to : %d", n);
app::Clusters::IlluminanceMeasurement::Attributes::MeasuredValue::Set(1, static_cast<int16_t>(n));
}
else if (name == "Humidity")
{
// update the current humidity here for hardcoded endpoint 1
ESP_LOGI(TAG, "Humidity changed to : %d", n);
app::Clusters::RelativeHumidityMeasurement::Attributes::MeasuredValue::Set(1, static_cast<int16_t>(n * 100));
}
else if (name == "CoolSetpoint")
{
// update the occupied cooling setpoint for hardcoded endpoint 1
ESP_LOGI(TAG, "Occupied Cooling Setpoint changed to : %d", n);
app::Clusters::Thermostat::Attributes::OccupiedCoolingSetpoint::Set(1, static_cast<int16_t>(n * 100));
}
else if (name == "HeatSetpoint")
{
// update the occupied heating setpoint for hardcoded endpoint 1
ESP_LOGI(TAG, "Occupied Heating Setpoint changed to : %d", n);
app::Clusters::Thermostat::Attributes::OccupiedHeatingSetpoint::Set(1, static_cast<int16_t>(n * 100));
}
else if (name == "SystemMode")
{
// System modes - Off, Auto, Cool and Heat are currently supported.
chip::app::Clusters::Thermostat::SystemModeEnum modeEnum =
chip::app::Clusters::Thermostat::SystemModeEnum::kUnknownEnumValue;
uint8_t mode = n;
switch (n)
{
case 0:
modeEnum = chip::app::Clusters::Thermostat::SystemModeEnum::kOff;
break;
case 1:
modeEnum = chip::app::Clusters::Thermostat::SystemModeEnum::kAuto;
break;
case 3:
modeEnum = chip::app::Clusters::Thermostat::SystemModeEnum::kCool;
break;
case 4:
modeEnum = chip::app::Clusters::Thermostat::SystemModeEnum::kHeat;
break;
case 5:
modeEnum = chip::app::Clusters::Thermostat::SystemModeEnum::kEmergencyHeat;
break;
case 6:
modeEnum = chip::app::Clusters::Thermostat::SystemModeEnum::kPrecooling;
break;
case 7:
modeEnum = chip::app::Clusters::Thermostat::SystemModeEnum::kFanOnly;
break;
case 8:
modeEnum = chip::app::Clusters::Thermostat::SystemModeEnum::kDry;
break;
case 9:
modeEnum = chip::app::Clusters::Thermostat::SystemModeEnum::kSleep;
break;
default:
modeEnum = chip::app::Clusters::Thermostat::SystemModeEnum::kUnknownEnumValue;
break;
}
// Update the system mode here for hardcoded endpoint 1
if (isValidThermostatSystemMode(mode))
{
ESP_LOGI(TAG, "System Mode changed to : %d", mode);
app::Clusters::Thermostat::Attributes::SystemMode::Set(1, modeEnum);
// If system mode is auto set running mode to off otherwise set it to what the system mode is set to
if (modeEnum == chip::app::Clusters::Thermostat::SystemModeEnum::kAuto)
{
app::Clusters::Thermostat::Attributes::ThermostatRunningMode::Set(
1, chip::app::Clusters::Thermostat::ThermostatRunningModeEnum::kOff);
}
else
{
if (isValidThermostatRunningMode(mode))
{
ESP_LOGI(TAG, "Running Mode changed to : %d", mode);
chip::app::Clusters::Thermostat::ThermostatRunningModeEnum runningModeEnum;
switch (mode)
{
case 0:
runningModeEnum = chip::app::Clusters::Thermostat::ThermostatRunningModeEnum::kOff;
break;
case 3:
runningModeEnum = chip::app::Clusters::Thermostat::ThermostatRunningModeEnum::kCool;
break;
case 4:
runningModeEnum = chip::app::Clusters::Thermostat::ThermostatRunningModeEnum::kHeat;
break;
default:
runningModeEnum = chip::app::Clusters::Thermostat::ThermostatRunningModeEnum::kUnknownEnumValue;
break;
}
app::Clusters::Thermostat::Attributes::ThermostatRunningMode::Set(1, runningModeEnum);
}
else
{
ESP_LOGI(TAG, "Running Mode %d is not valid", mode);
}
}
}
else
{
ESP_LOGI(TAG, "System Mode %d is not valid", mode);
}
}
else if (name == "RunningMode")
{
// Get the system mode
chip::app::Clusters::Thermostat::SystemModeEnum systemMode = chip::app::Clusters::Thermostat::SystemModeEnum::kOff;
app::Clusters::Thermostat::Attributes::SystemMode::Get(1, &systemMode);
if (systemMode != chip::app::Clusters::Thermostat::SystemModeEnum::kAuto)
{
ESP_LOGI(TAG, "Running mode can be changed only for system mode auto. Current system mode %d",
static_cast<int>(systemMode));
}
else
{
uint8_t mode = n;
chip::app::Clusters::Thermostat::ThermostatRunningModeEnum modeEnum =
chip::app::Clusters::Thermostat::ThermostatRunningModeEnum::kUnknownEnumValue;
// update the running mode here for hardcoded endpoint 1
if (isValidThermostatRunningMode(mode))
{
ESP_LOGI(TAG, "Running Mode changed to : %d", mode);
switch (n)
{
case 0:
modeEnum = chip::app::Clusters::Thermostat::ThermostatRunningModeEnum::kOff;
break;
case 3:
modeEnum = chip::app::Clusters::Thermostat::ThermostatRunningModeEnum::kCool;
break;
case 4:
modeEnum = chip::app::Clusters::Thermostat::ThermostatRunningModeEnum::kHeat;
break;
default:
modeEnum = chip::app::Clusters::Thermostat::ThermostatRunningModeEnum::kUnknownEnumValue;
break;
}
app::Clusters::Thermostat::Attributes::ThermostatRunningMode::Set(1, modeEnum);
}
else
{
ESP_LOGI(TAG, "Running Mode %d is not valid", mode);
}
}
}
else if (name == "Current Lift")
{
// update the current lift here for hardcoded endpoint 1
ESP_LOGI(TAG, "Current position lift percent 100ths changed to : %d", n * 100);
app::Clusters::WindowCovering::Attributes::CurrentPositionLiftPercent100ths::Set(1, static_cast<uint16_t>(n * 100));
}
else if (name == "Current Tilt")
{
// update the current tilt here for hardcoded endpoint 1
ESP_LOGI(TAG, "Current position tilt percent 100ths changed to : %d", n * 100);
app::Clusters::WindowCovering::Attributes::CurrentPositionTiltPercent100ths::Set(1, static_cast<uint16_t>(n * 100));
}
else if (name == "Opr Status")
{
// update the operational status here for hardcoded endpoint 1
ESP_LOGI(TAG, "Operational status changed to : %d", n);
chip::BitFlags<app::Clusters::WindowCovering::OperationalStatus> opStatus =
static_cast<chip::BitFlags<app::Clusters::WindowCovering::OperationalStatus>>(n);
app::Clusters::WindowCovering::Attributes::OperationalStatus::Set(1, opStatus);
}
else if (name == "Bat remaining")
{
// update the battery percent remaining here for hardcoded endpoint 1
ESP_LOGI(TAG, "Battery percent remaining changed to : %d", n);
app::Clusters::PowerSource::Attributes::BatPercentRemaining::Set(1, static_cast<uint8_t>(n * 2));
}
value = buffer;
}
else if (IsBooleanAttribute())
{
auto & name = std::get<0>(attribute);
auto & cluster = std::get<0>(std::get<1>(std::get<1>(devices[deviceIndex])[endpointIndex])[i]);
if (name == "OnOff" && cluster == "OnOff")
{
value = (value == "On") ? "Off" : "On";
bool attributeValue = (value == "On");
app::Clusters::OnOff::Attributes::OnOff::Set(endpointIndex + 1, attributeValue);
}
if (name == "Occupancy" && cluster == "Occupancy Sensor")
{
value = (value == "Yes") ? "No" : "Yes";
bool attributeValue = (value == "Yes");
ESP_LOGI(TAG, "Occupancy changed to : %s", value.c_str());
// update the current occupancy here for hardcoded endpoint 1
app::Clusters::OccupancySensing::Attributes::Occupancy::Set(1, attributeValue);
}
}
else
{
auto & name = std::get<0>(attribute);
auto & cluster = std::get<0>(std::get<1>(std::get<1>(devices[deviceIndex])[endpointIndex])[0]);
ESP_LOGI(TAG, "editing attribute as string: '%s' (%s)", value.c_str(), i == 0 ? "+" : "-");
ESP_LOGI(TAG, "name and cluster: '%s' (%s)", name.c_str(), cluster.c_str());
if (name == "Charge level" && cluster == "Power Source")
{
using namespace chip::app::Clusters::PowerSource;
auto attributeValue = BatChargeLevelEnum::kOk;
if (value == "OK")
{
value = "Warning";
attributeValue = BatChargeLevelEnum::kWarning;
}
else if (value == "Warning")
{
value = "Critical";
attributeValue = BatChargeLevelEnum::kCritical;
}
else
{
value = "OK";
attributeValue = BatChargeLevelEnum::kOk;
}
// update the battery charge level here for hardcoded endpoint 1
ESP_LOGI(TAG, "Battery charge level changed to : %u", static_cast<uint8_t>(attributeValue));
app::Clusters::PowerSource::Attributes::BatChargeLevel::Set(1, attributeValue);
}
else
{
value = (value == "Closed") ? "Open" : "Closed";
}
}
}
};
class AttributeListModel : public ListScreen::Model
{
int deviceIndex;
int endpointIndex;
int clusterIndex;
public:
AttributeListModel(int deviceIndex, int endpointIndex, int clusterIndex) :
deviceIndex(deviceIndex), endpointIndex(endpointIndex), clusterIndex(clusterIndex)
{}
virtual std::string GetTitle() { return "Attributes"; }
virtual int GetItemCount()
{
return std::get<1>(std::get<1>(std::get<1>(devices[deviceIndex])[endpointIndex])[clusterIndex]).size();
}
virtual std::string GetItemText(int i)
{
auto & attribute = std::get<1>(std::get<1>(std::get<1>(devices[deviceIndex])[endpointIndex])[clusterIndex])[i];
auto & name = std::get<0>(attribute);
auto & value = std::get<1>(attribute);
char buffer[64];
snprintf(buffer, sizeof(buffer), "%s : %s", name.c_str(), value.c_str());
return buffer;
}
virtual void ItemAction(int i)
{
ESP_LOGI(TAG, "Opening attribute %d", i);
ScreenManager::PushScreen(chip::Platform::New<ListScreen>(
chip::Platform::New<EditAttributeListModel>(deviceIndex, endpointIndex, clusterIndex, i)));
}
};
class ClusterListModel : public ListScreen::Model
{
int deviceIndex;
int endpointIndex;
public:
ClusterListModel(int deviceIndex, int endpointIndex) : deviceIndex(deviceIndex), endpointIndex(endpointIndex) {}
virtual std::string GetTitle() { return "Clusters"; }
virtual int GetItemCount() { return std::get<1>(std::get<1>(devices[deviceIndex])[endpointIndex]).size(); }
virtual std::string GetItemText(int i) { return std::get<0>(std::get<1>(std::get<1>(devices[deviceIndex])[endpointIndex])[i]); }
virtual void ItemAction(int i)
{
ESP_LOGI(TAG, "Opening cluster %d", i);
ScreenManager::PushScreen(
chip::Platform::New<ListScreen>(chip::Platform::New<AttributeListModel>(deviceIndex, endpointIndex, i)));
}
};
class EndpointListModel : public ListScreen::Model
{
int deviceIndex;
public:
EndpointListModel(int deviceIndex) : deviceIndex(deviceIndex) {}
virtual std::string GetTitle() { return "Endpoints"; }
virtual int GetItemCount() { return std::get<1>(devices[deviceIndex]).size(); }
virtual std::string GetItemText(int i) { return std::get<0>(std::get<1>(devices[deviceIndex])[i]); }
virtual void ItemAction(int i)
{
ESP_LOGI(TAG, "Opening endpoint %d", i);
ScreenManager::PushScreen(chip::Platform::New<ListScreen>(chip::Platform::New<ClusterListModel>(deviceIndex, i)));
}
};
class DeviceListModel : public ListScreen::Model
{
public:
virtual std::string GetTitle() { return "Devices"; }
virtual int GetItemCount() { return devices.size(); }
virtual std::string GetItemText(int i) { return std::get<0>(devices[i]); }
virtual void ItemAction(int i)
{
ESP_LOGI(TAG, "Opening device %d", i);
ScreenManager::PushScreen(chip::Platform::New<ListScreen>(chip::Platform::New<EndpointListModel>(i)));
}
};
class ActionListModel : public ListScreen::Model
{
int GetItemCount() override { return static_cast<int>(mActions.size()); }
std::string GetItemText(int i) override { return mActions[i].title.c_str(); }
void ItemAction(int i) override
{
ESP_LOGI(TAG, "generic action %d", i);
mActions[i].action();
}
protected:
void AddAction(const char * name, std::function<void(void)> action) { mActions.push_back(Action(name, action)); }
private:
struct Action
{
std::string title;
std::function<void(void)> action;
Action(const char * t, std::function<void(void)> a) : title(t), action(a) {}
};
std::vector<Action> mActions;
};
class MdnsDebugListModel : public ActionListModel
{
public:
std::string GetTitle() override { return "mDNS Debug"; }
MdnsDebugListModel() { AddAction("(Re-)Init", std::bind(&MdnsDebugListModel::DoReinit, this)); }
private:
void DoReinit()
{
CHIP_ERROR err = Dnssd::ServiceAdvertiser::Instance().Init(DeviceLayer::UDPEndPointManager());
if (err != CHIP_NO_ERROR)
{
ESP_LOGE(TAG, "Error initializing: %s", err.AsString());
}
}
};
class SetupListModel : public TouchesMatterStackModel
{
public:
SetupListModel()
{
std::string resetWiFi = "Reset WiFi";
std::string resetToFactory = "Reset to factory";
std::string forceWiFiCommissioningBasic = "Force WiFi commissioning (basic)";
options.emplace_back(resetWiFi);
options.emplace_back(resetToFactory);
options.emplace_back(forceWiFiCommissioningBasic);
}
virtual std::string GetTitle() { return "Setup"; }
virtual int GetItemCount() { return options.size(); }
virtual std::string GetItemText(int i) { return options.at(i); }
void DoAction(int i) override
{
ESP_LOGI(TAG, "Opening options %d: %s", i, GetItemText(i).c_str());
if (i == 0)
{
ConnectivityMgr().ClearWiFiStationProvision();
chip::Server::GetInstance().GetFabricTable().DeleteAllFabrics();
chip::Server::GetInstance().GetCommissioningWindowManager().OpenBasicCommissioningWindow();
}
else if (i == 1)
{
chip::Server::GetInstance().ScheduleFactoryReset();
}
else if (i == 2)
{
chip::Server::GetInstance().GetFabricTable().DeleteAllFabrics();
auto & commissionMgr = chip::Server::GetInstance().GetCommissioningWindowManager();
commissionMgr.OpenBasicCommissioningWindow(commissionMgr.MaxCommissioningTimeout(),
CommissioningWindowAdvertisement::kDnssdOnly);
}
}
private:
std::vector<std::string> options;
};
void SetupPretendDevices()
{
AddDevice("Watch");
AddEndpoint("Default");
AddCluster("Battery");
AddAttribute("Level", "89");
AddAttribute("Voltage", "490");
AddAttribute("Amperage", "501");
AddCluster("Heart Monitor");
AddAttribute("BPM", "72");
AddCluster("Step Counter");
AddAttribute("Steps", "9876");
AddDevice("Light Bulb");
AddEndpoint("1");
AddCluster("OnOff");
AddAttribute("OnOff", "Off");
AddCluster("Level Control");
AddAttribute("Current Level", "255");
AddEndpoint("2");
AddCluster("OnOff");
AddAttribute("OnOff", "Off");
AddCluster("Level Control");
AddAttribute("Current Level", "255");
AddDevice("Thermometer");
AddEndpoint("External");
AddCluster("Thermometer");
AddAttribute("Temperature", "21");
// write the temp attribute
chip::app::Clusters::TemperatureMeasurement::Attributes::MeasuredValue::Set(1, static_cast<int16_t>(21 * 100));
AddDevice("Garage 1");
AddEndpoint("Door 1");
AddCluster("Door");
AddAttribute("State", "Closed");
AddEndpoint("Door 2");
AddCluster("Door");
AddAttribute("State", "Closed");
AddEndpoint("Door 3");
AddCluster("Door");
AddAttribute("State", "Open");
AddDevice("Garage 2");
AddEndpoint("Door 1");
AddCluster("Door");
AddAttribute("State", "Open");
AddEndpoint("Door 2");
AddCluster("Door");
AddAttribute("State", "Closed");
AddDevice("Occupancy Sensor");
AddEndpoint("External");
AddCluster("Occupancy Sensor");
AddAttribute("Occupancy", "Yes");
app::Clusters::OccupancySensing::Attributes::Occupancy::Set(1, 1);
AddDevice("Contact Sensor");
AddEndpoint("External");
AddCluster("Contact Sensor");
AddAttribute("Contact", "true");
app::Clusters::BooleanState::Attributes::StateValue::Set(1, true);
AddDevice("Thermostat");
AddEndpoint("1");
AddCluster("Thermostat");
app::Clusters::TemperatureMeasurement::Attributes::MeasuredValue::Set(1, static_cast<int16_t>(21 * 100));
app::Clusters::Thermostat::Attributes::LocalTemperature::Set(1, static_cast<int16_t>(21 * 100));
AddAttribute("SystemMode", "4");
app::Clusters::Thermostat::Attributes::SystemMode::Set(1, chip::app::Clusters::Thermostat::SystemModeEnum::kHeat);
AddAttribute("CoolSetpoint", "19");
app::Clusters::Thermostat::Attributes::OccupiedCoolingSetpoint::Set(1, static_cast<int16_t>(19 * 100));
AddAttribute("HeatSetpoint", "25");
app::Clusters::Thermostat::Attributes::OccupiedHeatingSetpoint::Set(1, static_cast<int16_t>(25 * 100));
AddAttribute("RunningMode", "4");
app::Clusters::Thermostat::Attributes::ThermostatRunningMode::Set(
1, chip::app::Clusters::Thermostat::ThermostatRunningModeEnum::kHeat);
AddDevice("Humidity Sensor");
AddEndpoint("External");
AddCluster("Humidity Sensor");
AddAttribute("Humidity", "30");
app::Clusters::RelativeHumidityMeasurement::Attributes::MeasuredValue::Set(1, static_cast<int16_t>(30 * 100));
AddDevice("Light Sensor");
AddEndpoint("External");
AddCluster("Illuminance Measurement");
AddAttribute("Illuminance", "1000");
app::Clusters::IlluminanceMeasurement::Attributes::MeasuredValue::Set(1, static_cast<int16_t>(1000));
AddDevice("Color Light");
AddEndpoint("1");
AddCluster("OnOff");
AddAttribute("OnOff", "Off");
app::Clusters::OnOff::Attributes::OnOff::Set(1, false);
AddCluster("Level Control");
AddAttribute("Color Current Level", "255");
app::Clusters::LevelControl::Attributes::CurrentLevel::Set(1, 255);
AddEndpoint("2");
AddCluster("Color Control");
AddAttribute("Current Hue", "200");
app::Clusters::ColorControl::Attributes::CurrentHue::Set(1, 200);
AddAttribute("Current Saturation\n", "150");
app::Clusters::ColorControl::Attributes::CurrentSaturation::Set(1, 150);
AddDevice("Window Covering");
AddEndpoint("1");
AddCluster("Window Covering");
AddAttribute("Current Lift", "5");
app::Clusters::WindowCovering::Attributes::CurrentPositionLiftPercent100ths::Set(1, static_cast<uint16_t>(5 * 100));
AddAttribute("Current Tilt", "5");
app::Clusters::WindowCovering::Attributes::CurrentPositionTiltPercent100ths::Set(1, static_cast<uint16_t>(5 * 100));
AddAttribute("Opr Status", "0");
chip::BitFlags<app::Clusters::WindowCovering::OperationalStatus> opStatus =
static_cast<chip::BitFlags<app::Clusters::WindowCovering::OperationalStatus>>(0);
app::Clusters::WindowCovering::Attributes::OperationalStatus::Set(1, opStatus);
AddDevice("Battery");
AddEndpoint("1");
AddCluster("Power Source");
AddAttribute("Bat remaining", "70");
app::Clusters::PowerSource::Attributes::BatPercentRemaining::Set(1, static_cast<uint8_t>(70 * 2));
AddAttribute("Charge level", "0");
app::Clusters::PowerSource::Attributes::BatChargeLevel::Set(1, app::Clusters::PowerSource::BatChargeLevelEnum::kOk);
}
esp_err_t InitM5Stack(std::string qrCodeText)
{
esp_err_t err;
// Initialize the buttons.
err = gpio_install_isr_service(0);
ESP_RETURN_ON_ERROR(err, TAG, "Button preInit failed: %s", esp_err_to_name(err));
for (int i = 0; i < BUTTON_NUMBER; ++i)
{
err = gButtons[i].Init();
ESP_RETURN_ON_ERROR(err, TAG, "Button.Init() failed: %s", esp_err_to_name(err));
}
// Push a rudimentary user interface.
ScreenManager::PushScreen(chip::Platform::New<ListScreen>(
(chip::Platform::New<SimpleListModel>())
->Title("CHIP")
->Action([](int i) { ESP_LOGI(TAG, "action on item %d", i); })
->Item("Devices",
[]() {
ESP_LOGI(TAG, "Opening device list");
ScreenManager::PushScreen(chip::Platform::New<ListScreen>(chip::Platform::New<DeviceListModel>()));
})
->Item("mDNS Debug",
[]() {
ESP_LOGI(TAG, "Opening MDNS debug");
ScreenManager::PushScreen(chip::Platform::New<ListScreen>(chip::Platform::New<MdnsDebugListModel>()));
})
->Item("QR Code",
[=]() {
ESP_LOGI(TAG, "Opening QR code screen");
PrintOnboardingCodes(chip::RendezvousInformationFlags(CONFIG_RENDEZVOUS_MODE));
ScreenManager::PushScreen(chip::Platform::New<QRCodeScreen>(qrCodeText));
})
->Item("Setup",
[=]() {
ESP_LOGI(TAG, "Opening Setup list");
ScreenManager::PushScreen(chip::Platform::New<ListScreen>(chip::Platform::New<SetupListModel>()));
})
->Item("Status", [=]() {
ESP_LOGI(TAG, "Opening Status screen");
ScreenManager::PushScreen(chip::Platform::New<StatusScreen>());
})));
return ESP_OK;
}
#endif
void InitDeviceDisplay()
{
// Create buffer for QR code that can fit max size and null terminator.
char qrCodeBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1];
chip::MutableCharSpan qrCodeText(qrCodeBuffer);
// Get QR Code and emulate its content using NFC tag
GetQRCode(qrCodeText, chip::RendezvousInformationFlags(CONFIG_RENDEZVOUS_MODE));
// Initialize the display device.
esp_err_t err = InitDisplay();
if (err != ESP_OK)
{
ESP_LOGE(TAG, "InitDisplay() failed: %s", esp_err_to_name(err));
return;
}
// Initialize the screen manager
ScreenManager::Init();
// Connect the status LED to VLEDs.
int vled1 = ScreenManager::AddVLED(TFT_GREEN);
int vled2 = ScreenManager::AddVLED(TFT_RED);
statusLED1.SetVLED(vled1, vled2);
int vled3 = ScreenManager::AddVLED(TFT_CYAN);
int vled4 = ScreenManager::AddVLED(TFT_ORANGE);
statusLED2.SetVLED(vled3, vled4);
bluetoothLED.SetVLED(ScreenManager::AddVLED(TFT_BLUE));
wifiLED.SetVLED(ScreenManager::AddVLED(TFT_YELLOW));
pairingWindowLED.SetVLED(ScreenManager::AddVLED(TFT_ORANGE));
#if CONFIG_DEVICE_TYPE_M5STACK
InitM5Stack(qrCodeText.data());
#elif CONFIG_DEVICE_TYPE_ESP32_WROVER_KIT
// Display the QR Code
QRCodeScreen qrCodeScreen(qrCodeText.data());
qrCodeScreen.Display();
#endif
}
#endif