1 /*
2 * Copyright (c) 2022 HiSilicon (Shanghai) Technologies CO., LIMITED.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <hi_mem.h>
17 #include <cJSON.h>
18 #include <string.h>
19 #include "iot_main.h"
20 #include "iot_log.h"
21 #include "iot_config.h"
22 #include "iot_profile.h"
23
24 // < format the report data to json string mode
FormatProfileValue(IoTProfileKV_t * kv)25 static cJSON *FormatProfileValue(IoTProfileKV_t *kv)
26 {
27 cJSON *ret = NULL;
28 switch (kv->type) {
29 case EN_IOT_DATATYPE_INT:
30 ret = cJSON_CreateNumber(kv->iValue);
31 break;
32 case EN_IOT_DATATYPE_LONG:
33 ret = cJSON_CreateNumber((double)(*(long *)kv->value));
34 break;
35 case EN_IOT_DATATYPE_STRING:
36 ret = cJSON_CreateString((const char *)kv->value);
37 break;
38 default:
39 break;
40 }
41 return ret;
42 }
43
MakeKvs(IoTProfileKV_t * kvlst)44 static cJSON *MakeKvs(IoTProfileKV_t *kvlst)
45 {
46 cJSON *root;
47 cJSON *kv;
48 IoTProfileKV_t *kvInfo;
49
50 // < build a root node
51 root = cJSON_CreateObject();
52 if (root == NULL) {
53 cJSON_Delete(root);
54 root = NULL;
55 return root;
56 }
57 // < add all the property to the properties
58 kvInfo = kvlst;
59 while (kvInfo != NULL) {
60 kv = FormatProfileValue(kvInfo);
61 if (kv == NULL) {
62 if (root != NULL) {
63 cJSON_Delete(root);
64 root = NULL;
65 }
66 return root;
67 }
68 cJSON_AddItemToObject(root, kvInfo->key, kv);
69 kvInfo = kvInfo->nxt;
70 }
71 // < OK, now we return it
72 return root;
73 }
74
75 #define CN_PROFILE_SERVICE_KEY_SERVICEID "service_id"
76 #define CN_PROFILE_SERVICE_KEY_PROPERTIIES "properties"
77 #define CN_PROFILE_SERVICE_KEY_EVENTTIME "event_time"
78 #define CN_PROFILE_KEY_SERVICES "services"
MakeService(IoTProfileService_t * serviceInfo)79 static cJSON *MakeService(IoTProfileService_t *serviceInfo)
80 {
81 cJSON *root;
82 cJSON *serviceID;
83 cJSON *properties;
84 cJSON *eventTime;
85
86 // < build a root node
87 root = cJSON_CreateObject();
88 if (root == NULL) {
89 cJSON_Delete(root);
90 root = NULL;
91 return root;
92 }
93 // < add the serviceID node to the root node
94 serviceID = cJSON_CreateString(serviceInfo->serviceID);
95 if (serviceID == NULL) {
96 if (root != NULL) {
97 cJSON_Delete(root);
98 root = NULL;
99 }
100 return root;
101 }
102 cJSON_AddItemToObjectCS(root, CN_PROFILE_SERVICE_KEY_SERVICEID, serviceID);
103 // < add the properties node to the root
104 properties = MakeKvs(serviceInfo->serviceProperty);
105 if (properties == NULL) {
106 if (root != NULL) {
107 cJSON_Delete(root);
108 root = NULL;
109 }
110 return root;
111 }
112 cJSON_AddItemToObjectCS(root, CN_PROFILE_SERVICE_KEY_PROPERTIIES, properties);
113 // < add the event time (optional) to the root
114 if (serviceInfo->eventTime != NULL) {
115 eventTime = cJSON_CreateString(serviceInfo->eventTime);
116 if (eventTime == NULL) {
117 if (root != NULL) {
118 cJSON_Delete(root);
119 root = NULL;
120 }
121 return root;
122 }
123 cJSON_AddItemToObjectCS(root, CN_PROFILE_SERVICE_KEY_EVENTTIME, eventTime);
124 }
125 // < OK, now we return it
126 cJSON_Delete(properties);
127 return root;
128 }
129
MakeServices(IoTProfileService_t * serviceInfo)130 static cJSON *MakeServices(IoTProfileService_t *serviceInfo)
131 {
132 cJSON *services = NULL;
133 cJSON *service;
134 IoTProfileService_t *serviceTmp;
135
136 // < create the services array node
137 services = cJSON_CreateArray();
138 if (services == NULL) {
139 cJSON_Delete(services);
140 services = NULL;
141 return services;
142 }
143
144 serviceTmp = serviceInfo;
145 while (serviceTmp != NULL) {
146 service = MakeService(serviceTmp);
147 if (service == NULL) {
148 if (services != NULL) {
149 cJSON_Delete(services);
150 services = NULL;
151 }
152 return services;
153 }
154 cJSON_AddItemToArray(services, service);
155 serviceTmp = serviceTmp->nxt;
156 }
157 // < now we return the services
158 return services;
159 }
160
161 // < use this function to make a topic to publish
162 // < if request_id is needed depends on the fmt
MakeTopic(const char * fmt,const char * deviceID,const char * requestID)163 static char *MakeTopic(const char *fmt, const char *deviceID, const char *requestID)
164 {
165 int len;
166 char *ret = NULL;
167
168 len = strlen(fmt) + strlen(deviceID);
169 if (requestID != NULL) {
170 len += strlen(requestID);
171 }
172
173 ret = hi_malloc(0, len);
174 if (ret != NULL) {
175 if (requestID != NULL) {
176 (void)snprintf_s(ret, len, len, fmt, deviceID, requestID);
177 } else {
178 (void)snprintf_s(ret, len, len, fmt, deviceID);
179 }
180 }
181 return ret;
182 }
183
184 #define CN_PROFILE_CMDRESP_KEY_RETCODE "result_code"
185 #define CN_PROFILE_CMDRESP_KEY_RESPNAME "response_name"
186 #define CN_PROFILE_CMDRESP_KEY_PARAS "paras"
MakeProfileCmdResp(IoTCmdResp_t * payload)187 static char *MakeProfileCmdResp(IoTCmdResp_t *payload)
188 {
189 char *ret = NULL;
190 cJSON *root;
191 cJSON *retCode;
192 cJSON *respName;
193 cJSON *paras;
194
195 // < create the root node
196 root = cJSON_CreateObject();
197 if (root == NULL) {
198 cJSON_Delete(root);
199 return ret;
200 }
201 // < create retcode and retdesc and add it to the root
202 retCode = cJSON_CreateNumber(payload->retCode);
203 if (retCode == NULL) {
204 if (root != NULL) {
205 cJSON_Delete(root);
206 }
207 return ret;
208 }
209 cJSON_AddItemToObjectCS(root, CN_PROFILE_CMDRESP_KEY_RETCODE, retCode);
210 if (payload->respName != NULL) {
211 respName = cJSON_CreateString(payload->respName);
212 if (respName == NULL) {
213 if (root != NULL) {
214 cJSON_Delete(root);
215 }
216 return ret;
217 }
218 cJSON_AddItemToObjectCS(root, CN_PROFILE_CMDRESP_KEY_RESPNAME, respName);
219 }
220
221 if (payload->paras != NULL) {
222 paras = MakeKvs(payload->paras);
223 if (paras == NULL) {
224 if (root != NULL) {
225 cJSON_Delete(root);
226 }
227 return ret;
228 }
229 cJSON_AddItemToObjectCS(root, CN_PROFILE_CMDRESP_KEY_PARAS, paras);
230 }
231 // < OK, now we make it to a buffer
232 ret = cJSON_PrintUnformatted(root);
233 cJSON_Delete(root);
234 return ret;
235 }
236
MakeProfilePropertyReport(IoTProfileService_t * payload)237 static char *MakeProfilePropertyReport(IoTProfileService_t *payload)
238 {
239 char *ret = NULL;
240 cJSON *root;
241 cJSON *services;
242
243 // < create the root node
244 root = cJSON_CreateObject();
245 if (root == NULL) {
246 cJSON_Delete(root);
247 return ret;
248 }
249 // < create the services array node to the root
250 services = MakeServices(payload);
251 if (services == NULL) {
252 if (root != NULL) {
253 cJSON_Delete(root);
254 }
255 return ret;
256 }
257 cJSON_AddItemToObjectCS(root, CN_PROFILE_KEY_SERVICES, services);
258 // < OK, now we make it to a buffer
259 ret = cJSON_PrintUnformatted(root);
260 cJSON_Delete(root);
261 return ret;
262 }
263
264 #define WECHAT_SUBSCRIBE_TYPE "update"
265 #define WECHAT_SUBSCRIBE_VERSION "1.0.0"
266 #define WECHAT_SUBSCRIBE_TOKEN "DeviceSubscribe"
MakeProfileReport(WeChatProfile * payload)267 static char *MakeProfileReport(WeChatProfile *payload)
268 {
269 char *ret = NULL;
270 cJSON *root;
271 cJSON *state;
272 cJSON *reported;
273
274 /* create json root node */
275 root = cJSON_CreateObject();
276 if (root == NULL) {
277 return;
278 }
279 /* state create */
280 state = cJSON_CreateObject();
281 if (state == NULL) {
282 return;
283 }
284 /* reported create */
285 reported = cJSON_CreateObject();
286 if (reported == NULL) {
287 return;
288 }
289 /* add root object */
290 cJSON_AddItemToObject(root, payload->subscribeType, cJSON_CreateString(WECHAT_SUBSCRIBE_TYPE));
291 cJSON_AddItemToObject(root, payload->status.subState, state);
292 cJSON_AddItemToObject(state, payload->status.subReport, reported);
293 cJSON_AddItemToObject(root, payload->status.reportVersion, cJSON_CreateString(WECHAT_SUBSCRIBE_VERSION));
294 cJSON_AddItemToObject(root, payload->status.Token, cJSON_CreateString(WECHAT_SUBSCRIBE_TOKEN));
295 /* add reported item */
296 cJSON_AddNumberToObject(reported, payload->reportAction.subDeviceActionLight,
297 payload->reportAction.lightActionStatus);
298 cJSON_AddNumberToObject(reported, payload->reportAction.subDeviceActionMotor,
299 payload->reportAction.motorActionStatus);
300 cJSON_AddNumberToObject(reported, payload->reportAction.subDeviceActionTemperature,
301 payload->reportAction.temperatureData);
302 cJSON_AddNumberToObject(reported, payload->reportAction.subDeviceActionHumidity,
303 payload->reportAction.humidityActionData);
304 cJSON_AddNumberToObject(reported, payload->reportAction.subDeviceActionLightIntensity,
305 payload->reportAction.lightIntensityActionData);
306 ret = cJSON_PrintUnformatted(root);
307 cJSON_Delete(state);
308 cJSON_Delete(reported);
309 cJSON_Delete(root);
310 return ret;
311 }
312
313 #define CN_PROFILE_TOPICFMT_TOPIC "$shadow/operation/19VUBHD786/mqtt"
IoTProfilePropertyReport(char * deviceID,WeChatProfile * payload)314 int IoTProfilePropertyReport(char *deviceID, WeChatProfile *payload)
315 {
316 int ret = -1;
317 char *topic;
318 char *msg;
319
320 if ((deviceID == NULL) || (payload== NULL)) {
321 return ret;
322 }
323 topic = MakeTopic(CN_PROFILE_TOPICFMT_TOPIC, deviceID, NULL);
324 if (topic == NULL) {
325 return;
326 }
327 msg = MakeProfileReport(payload);
328 if ((topic != NULL) && (msg != NULL)) {
329 ret = IotSendMsg(0, topic, msg);
330 }
331
332 hi_free(0, topic);
333 cJSON_free(msg);
334
335 return ret;
336 }