|
| 1 | +#include "Matter.h" |
| 2 | +#include <app/server/OnboardingCodesUtil.h> |
| 3 | +using namespace chip; |
| 4 | +using namespace chip::app::Clusters; |
| 5 | +using namespace esp_matter; |
| 6 | +using namespace esp_matter::endpoint; |
| 7 | + |
| 8 | +/** |
| 9 | + * This program presents example Matter plugin unit (switch) device with two endpoints |
| 10 | + * with OnOff clusters by controlling LEDs with Matter and toggle buttons. |
| 11 | + * |
| 12 | + * You can toggle plugin unit by both: |
| 13 | + * - Matter (via CHIPTool or other Matter controller) |
| 14 | + * - toggle button (with debouncing) |
| 15 | + */ |
| 16 | + |
| 17 | +// Please configure your PINs |
| 18 | +const int LED_PIN_1 = 2; |
| 19 | +const int LED_PIN_2 = 17; |
| 20 | +const int TOGGLE_BUTTON_PIN_1 = 0; |
| 21 | +const int TOGGLE_BUTTON_PIN_2 = 21; |
| 22 | + |
| 23 | +// Debounce for toggle button |
| 24 | +const int DEBOUNCE_DELAY = 500; |
| 25 | +int last_toggle; |
| 26 | + |
| 27 | +// Cluster and attribute ID used by Matter plugin unit device |
| 28 | +const uint32_t CLUSTER_ID = OnOff::Id; |
| 29 | +const uint32_t ATTRIBUTE_ID = OnOff::Attributes::OnOff::Id; |
| 30 | + |
| 31 | +// Endpoint and attribute ref that will be assigned to Matter device |
| 32 | +uint16_t plugin_unit_endpoint_id_1 = 0; |
| 33 | +uint16_t plugin_unit_endpoint_id_2 = 0; |
| 34 | +attribute_t *attribute_ref_1; |
| 35 | +attribute_t *attribute_ref_2; |
| 36 | + |
| 37 | +// There is possibility to listen for various device events, related for example |
| 38 | +// to setup process Leaved as empty for simplicity |
| 39 | +static void on_device_event(const ChipDeviceEvent *event, intptr_t arg) {} |
| 40 | +static esp_err_t on_identification(identification::callback_type_t type, |
| 41 | + uint16_t endpoint_id, uint8_t effect_id, |
| 42 | + void *priv_data) { |
| 43 | + return ESP_OK; |
| 44 | +} |
| 45 | + |
| 46 | +// Listener on attribute update requests. |
| 47 | +// In this example, when update is requested, path (endpoint, cluster and |
| 48 | +// attribute) is checked if it matches plugin unit attribute. If yes, LED changes |
| 49 | +// state to new one. |
| 50 | +static esp_err_t on_attribute_update(attribute::callback_type_t type, |
| 51 | + uint16_t endpoint_id, uint32_t cluster_id, |
| 52 | + uint32_t attribute_id, |
| 53 | + esp_matter_attr_val_t *val, |
| 54 | + void *priv_data) { |
| 55 | + if (type == attribute::PRE_UPDATE && cluster_id == CLUSTER_ID && attribute_id == ATTRIBUTE_ID) { |
| 56 | + // We got an plugin unit on/off attribute update! |
| 57 | + boolean new_state = val->val.b; |
| 58 | + if (endpoint_id == plugin_unit_endpoint_id_1) { |
| 59 | + digitalWrite(LED_PIN_1, new_state); |
| 60 | + } else if (endpoint_id == plugin_unit_endpoint_id_2) { |
| 61 | + digitalWrite(LED_PIN_2, new_state); |
| 62 | + } |
| 63 | + } |
| 64 | + return ESP_OK; |
| 65 | +} |
| 66 | + |
| 67 | +void setup() { |
| 68 | + Serial.begin(115200); |
| 69 | + pinMode(LED_PIN_1, OUTPUT); |
| 70 | + pinMode(LED_PIN_2, OUTPUT); |
| 71 | + pinMode(TOGGLE_BUTTON_PIN_1, INPUT); |
| 72 | + pinMode(TOGGLE_BUTTON_PIN_2, INPUT); |
| 73 | + |
| 74 | + // Enable debug logging |
| 75 | + esp_log_level_set("*", ESP_LOG_DEBUG); |
| 76 | + |
| 77 | + // Setup Matter node |
| 78 | + node::config_t node_config; |
| 79 | + node_t *node = |
| 80 | + node::create(&node_config, on_attribute_update, on_identification); |
| 81 | + |
| 82 | + // Setup Plugin unit endpoint / cluster / attributes with default values |
| 83 | + on_off_plugin_unit::config_t plugin_unit_config; |
| 84 | + plugin_unit_config.on_off.on_off = false; |
| 85 | + plugin_unit_config.on_off.lighting.start_up_on_off = false; |
| 86 | + endpoint_t *endpoint_1 = on_off_plugin_unit::create(node, &plugin_unit_config, |
| 87 | + ENDPOINT_FLAG_NONE, NULL); |
| 88 | + endpoint_t *endpoint_2 = on_off_plugin_unit::create(node, &plugin_unit_config, |
| 89 | + ENDPOINT_FLAG_NONE, NULL); |
| 90 | + |
| 91 | + // Save on/off attribute reference. It will be used to read attribute value |
| 92 | + // later. |
| 93 | + attribute_ref_1 = |
| 94 | + attribute::get(cluster::get(endpoint_1, CLUSTER_ID), ATTRIBUTE_ID); |
| 95 | + attribute_ref_2 = |
| 96 | + attribute::get(cluster::get(endpoint_2, CLUSTER_ID), ATTRIBUTE_ID); |
| 97 | + |
| 98 | + // Save generated endpoint id |
| 99 | + plugin_unit_endpoint_id_1 = endpoint::get_id(endpoint_1); |
| 100 | + plugin_unit_endpoint_id_2 = endpoint::get_id(endpoint_2); |
| 101 | + |
| 102 | + // Start Matter device |
| 103 | + esp_matter::start(on_device_event); |
| 104 | + |
| 105 | + // Print codes needed to setup Matter device |
| 106 | + PrintOnboardingCodes( |
| 107 | + chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)); |
| 108 | +} |
| 109 | + |
| 110 | +// Reads plugin unit on/off attribute value |
| 111 | +esp_matter_attr_val_t get_onoff_attribute_value(esp_matter::attribute_t *attribute_ref) { |
| 112 | + esp_matter_attr_val_t onoff_value = esp_matter_invalid(NULL); |
| 113 | + attribute::get_val(attribute_ref, &onoff_value); |
| 114 | + return onoff_value; |
| 115 | +} |
| 116 | + |
| 117 | +// Sets plugin unit on/off attribute value |
| 118 | +void set_onoff_attribute_value(esp_matter_attr_val_t *onoff_value, uint16_t plugin_unit_endpoint_id) { |
| 119 | + attribute::update(plugin_unit_endpoint_id, CLUSTER_ID, ATTRIBUTE_ID, onoff_value); |
| 120 | +} |
| 121 | + |
| 122 | +// When toggle plugin unit button is pressed (with debouncing), |
| 123 | +// plugin unit attribute value is changed |
| 124 | +void loop() { |
| 125 | + if ((millis() - last_toggle) > DEBOUNCE_DELAY) { |
| 126 | + if (!digitalRead(TOGGLE_BUTTON_PIN_1)) { |
| 127 | + last_toggle = millis(); |
| 128 | + // Read actual on/off value, invert it and set |
| 129 | + esp_matter_attr_val_t onoff_value = get_onoff_attribute_value(attribute_ref_1); |
| 130 | + onoff_value.val.b = !onoff_value.val.b; |
| 131 | + set_onoff_attribute_value(&onoff_value, plugin_unit_endpoint_id_1); |
| 132 | + } |
| 133 | + |
| 134 | + if (!digitalRead(TOGGLE_BUTTON_PIN_2)) { |
| 135 | + last_toggle = millis(); |
| 136 | + // Read actual on/off value, invert it and set |
| 137 | + esp_matter_attr_val_t onoff_value = get_onoff_attribute_value(attribute_ref_2); |
| 138 | + onoff_value.val.b = !onoff_value.val.b; |
| 139 | + set_onoff_attribute_value(&onoff_value, plugin_unit_endpoint_id_2); |
| 140 | + } |
| 141 | + } |
| 142 | +} |
0 commit comments