3 * Copyright (c) 2020 Project CHIP Authors
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
20 * @file DeviceCallbacks.cpp
22 * Implements all the callbacks to the application from the CHIP Stack
25 #include "DeviceCallbacks.h"
27 #include "CHIPDeviceManager.h"
29 #include "LEDWidget.h"
30 #include "WiFiWidget.h"
31 #include "esp_heap_caps.h"
33 #include "gen/attribute-id.h"
34 #include "gen/cluster-id.h"
35 #include <app/server/Mdns.h>
36 #include <app/util/basic-types.h>
37 #include <app/util/util.h>
38 #include <lib/mdns/Advertiser.h>
39 #include <support/CodeUtils.h>
41 static const char * TAG = "app-devicecallbacks";
43 using namespace ::chip;
44 using namespace ::chip::Inet;
45 using namespace ::chip::System;
46 using namespace ::chip::DeviceLayer;
48 uint32_t identifyTimerCount;
49 constexpr uint32_t kIdentifyTimerDelayMS = 250;
51 void DeviceCallbacks::DeviceEventCallback(const ChipDeviceEvent * event, intptr_t arg)
55 case DeviceEventType::kInternetConnectivityChange:
56 OnInternetConnectivityChange(event);
59 case DeviceEventType::kSessionEstablished:
60 OnSessionEstablished(event);
62 case DeviceEventType::kInterfaceIpAddressChanged:
63 if ((event->InterfaceIpAddressChanged.Type == InterfaceIpChangeType::kIpV4_Assigned) ||
64 (event->InterfaceIpAddressChanged.Type == InterfaceIpChangeType::kIpV6_Assigned))
66 // MDNS server restart on any ip assignment: if link local ipv6 is configured, that
67 // will not trigger a 'internet connectivity change' as there is no internet
68 // connectivity. MDNS still wants to refresh its listening interfaces to include the
69 // newly selected address.
70 chip::app::Mdns::StartServer();
75 ESP_LOGI(TAG, "Current free heap: %d\n", heap_caps_get_free_size(MALLOC_CAP_8BIT));
78 void DeviceCallbacks::PostAttributeChangeCallback(EndpointId endpointId, ClusterId clusterId, AttributeId attributeId, uint8_t mask,
79 uint16_t manufacturerCode, uint8_t type, uint8_t size, uint8_t * value)
81 ESP_LOGI(TAG, "PostAttributeChangeCallback - Cluster ID: '0x%04x', EndPoint ID: '0x%02x', Attribute ID: '0x%04x'", clusterId,
82 endpointId, attributeId);
86 case ZCL_ON_OFF_CLUSTER_ID:
87 OnOnOffPostAttributeChangeCallback(endpointId, attributeId, value);
90 case ZCL_IDENTIFY_CLUSTER_ID:
91 OnIdentifyPostAttributeChangeCallback(endpointId, attributeId, value);
95 ESP_LOGI(TAG, "Unhandled cluster ID: %d", clusterId);
99 ESP_LOGI(TAG, "Current free heap: %d\n", heap_caps_get_free_size(MALLOC_CAP_8BIT));
102 void DeviceCallbacks::OnInternetConnectivityChange(const ChipDeviceEvent * event)
104 if (event->InternetConnectivityChange.IPv4 == kConnectivity_Established)
106 ESP_LOGI(TAG, "Server ready at: %s:%d", event->InternetConnectivityChange.address, CHIP_PORT);
108 chip::app::Mdns::StartServer();
110 else if (event->InternetConnectivityChange.IPv4 == kConnectivity_Lost)
112 ESP_LOGE(TAG, "Lost IPv4 connectivity...");
115 if (event->InternetConnectivityChange.IPv6 == kConnectivity_Established)
117 ESP_LOGI(TAG, "IPv6 Server ready...");
118 chip::app::Mdns::StartServer();
120 else if (event->InternetConnectivityChange.IPv6 == kConnectivity_Lost)
122 ESP_LOGE(TAG, "Lost IPv6 connectivity...");
126 void DeviceCallbacks::OnSessionEstablished(const ChipDeviceEvent * event)
128 if (event->SessionEstablished.IsCommissioner)
130 ESP_LOGI(TAG, "Commissioner detected!");
134 void DeviceCallbacks::OnOnOffPostAttributeChangeCallback(EndpointId endpointId, AttributeId attributeId, uint8_t * value)
136 VerifyOrExit(attributeId == ZCL_ON_OFF_ATTRIBUTE_ID, ESP_LOGI(TAG, "Unhandled Attribute ID: '0x%04x", attributeId));
137 VerifyOrExit(endpointId == 1 || endpointId == 2, ESP_LOGE(TAG, "Unexpected EndPoint ID: `0x%02x'", endpointId));
139 // At this point we can assume that value points to a bool value.
140 endpointId == 1 ? statusLED1.Set(*value) : statusLED2.Set(*value);
146 void IdentifyTimerHandler(Layer * systemLayer, void * appState, Error error)
148 statusLED1.Animate();
150 if (identifyTimerCount)
152 SystemLayer.StartTimer(kIdentifyTimerDelayMS, IdentifyTimerHandler, appState);
153 // Decrement the timer count.
154 identifyTimerCount--;
158 void DeviceCallbacks::OnIdentifyPostAttributeChangeCallback(EndpointId endpointId, AttributeId attributeId, uint8_t * value)
160 VerifyOrExit(attributeId == ZCL_IDENTIFY_TIME_ATTRIBUTE_ID, ESP_LOGI(TAG, "Unhandled Attribute ID: '0x%04x", attributeId));
161 VerifyOrExit(endpointId == 1, ESP_LOGE(TAG, "Unexpected EndPoint ID: `0x%02x'", endpointId));
163 statusLED1.Blink(kIdentifyTimerDelayMS * 2);
165 // timerCount represents the number of callback executions before we stop the timer.
166 // value is expressed in seconds and the timer is fired every 250ms, so just multiply value by 4.
167 // Also, we want timerCount to be odd number, so the ligth state ends in the same state it starts.
168 identifyTimerCount = (*value) * 4;
170 SystemLayer.CancelTimer(IdentifyTimerHandler, this);
171 SystemLayer.StartTimer(kIdentifyTimerDelayMS, IdentifyTimerHandler, this);
177 bool emberAfBasicClusterMfgSpecificPingCallback(void)
179 emberAfSendDefaultResponse(emberAfCurrentCommand(), EMBER_ZCL_STATUS_SUCCESS);