fc9a1e9819058a57a018d2dd8ef71420b1772bd3
[platform/upstream/iotivity.git] / cloud / samples / client / airconditioner / aircon_controlee.cpp
1 #include <memory>
2 #include <iostream>
3 #include <stdexcept>
4 #include <condition_variable>
5 #include <map>
6 #include <vector>
7 #include <string>
8 #include <unistd.h>
9
10 #include "ocstack.h"
11 #include "ocpayload.h"
12 #include "RDClient.h"
13
14 #include <OCApi.h>
15 #include <OCPlatform.h>
16
17 using namespace OC;
18 using namespace std;
19
20 class Resource
21 {
22     public:
23         OCResourceHandle m_handle;
24         Resource(string uri, vector<string> rt, vector<string> itf)
25         {
26             m_representation.setUri(uri);
27             m_representation.setResourceTypes(rt);
28             m_representation.setResourceInterfaces(itf);
29         }
30
31         string getResourceUri()
32         {
33             return m_representation.getUri();
34         }
35
36         vector<string> getResourceType()
37         {
38             return m_representation.getResourceTypes();
39         }
40
41         vector<string> getInterfaces()
42         {
43             return m_representation.getResourceInterfaces();
44         }
45
46         OCRepresentation getRepresentation(void)
47         {
48             m_representation.clearChildren();
49             for (auto it = m_childResources.begin(); it != m_childResources.end(); it++)
50             {
51                 m_representation.addChild((*it)->getRepresentation());
52             }
53             return m_representation;
54         }
55
56         OCStackResult addChildResource(Resource  *childResource)
57         {
58             m_childResources.push_back(childResource);
59             return OCPlatform::bindResource(m_handle, childResource->m_handle);
60         }
61
62         OCStackResult sendRepresentation(shared_ptr<OCResourceRequest> pRequest)
63         {
64             auto pResponse = make_shared<OC::OCResourceResponse>();
65             pResponse->setRequestHandle(pRequest->getRequestHandle());
66             pResponse->setResourceHandle(pRequest->getResourceHandle());
67
68             // Check for query params (if any)
69             QueryParamsMap queryParamsMap = pRequest->getQueryParameters();
70
71             cout << "\t\t\tquery params: \n";
72             for (auto it = queryParamsMap.begin(); it != queryParamsMap.end(); it++)
73             {
74                 cout << "\t\t\t\t" << it->first << ":" << it->second << endl;
75             }
76
77             auto findRes = queryParamsMap.find("if");
78
79             if (findRes != queryParamsMap.end())
80             {
81                 pResponse->setResourceRepresentation(getRepresentation(), findRes->second);
82             }
83             else
84             {
85                 pResponse->setResourceRepresentation(getRepresentation(), DEFAULT_INTERFACE);
86             }
87
88             pResponse->setResponseResult(OC_EH_OK);
89
90             return OCPlatform::sendResponse(pResponse);
91         }
92
93         OCStackResult propagate()
94         {
95             if (m_interestedObservers.size() > 0)
96             {
97                 shared_ptr<OCResourceResponse> resourceResponse =
98                 { make_shared<OCResourceResponse>() };
99
100                 resourceResponse->setResourceRepresentation(getRepresentation(), DEFAULT_INTERFACE);
101
102                 return OCPlatform::notifyListOfObservers(m_handle,
103                         m_interestedObservers,
104                         resourceResponse);
105             }
106
107             return OC_STACK_OK;
108         }
109
110         virtual OCEntityHandlerResult entityHandler(shared_ptr<OCResourceRequest> request) = 0;
111
112     protected:
113         OCRepresentation    m_representation;
114         vector<Resource *>  m_childResources;
115         ObservationIds      m_interestedObservers;
116 };
117
118 class BinarySwitchResource : public Resource //oic.r.switch.binary
119 {
120     private:
121         bool m_value;
122
123     public:
124         BinarySwitchResource(string uri, vector<string> rt, vector<string> itf)
125             : Resource(uri, rt, itf)
126         {
127             m_value = false;
128             m_representation.setValue("value", m_value);
129         }
130
131         void setBinarySwitchRepresentation(OCRepresentation &rep)
132         {
133             bool value;
134             if (rep.getValue("value", value))
135             {
136                 m_value = value;
137                 m_representation.setValue("value", m_value);
138                 cout << "\t\t\t\t" << "value: " << m_value << endl;
139
140                 propagate();
141             }
142         }
143
144         OCEntityHandlerResult entityHandler(shared_ptr<OCResourceRequest> request)
145         {
146             cout << "\tIn Server Binaryswitch entity handler:\n";
147             OCEntityHandlerResult ehResult = OC_EH_ERROR;
148
149             if (request)
150             {
151                 // Get the request type and request flag
152                 string requestType = request->getRequestType();
153                 int requestFlag = request->getRequestHandlerFlag();
154
155                 if (requestFlag & RequestHandlerFlag::RequestFlag)
156                 {
157                     cout << "\t\trequestFlag : Request\n";
158
159                     // If the request type is GET
160                     if (requestType == "GET")
161                     {
162                         cout << "\t\t\trequestType : GET\n";
163                         if (OC_STACK_OK == sendRepresentation(request))
164                         {
165                             ehResult = OC_EH_OK;
166                         }
167                     }
168                     else if (requestType == "PUT")
169                     {
170                         cout << "\t\t\trequestType : PUT\n";
171                         // PUT request operations
172                     }
173                     else if (requestType == "POST")
174                     {
175                         cout << "\t\t\trequestType : POST\n";
176                         // POST request operations
177                         OCRepresentation    rep = request->getResourceRepresentation();
178                         setBinarySwitchRepresentation(rep);
179
180                         if (OC_STACK_OK == sendRepresentation(request))
181                         {
182                             ehResult = OC_EH_OK;
183                         }
184                     }
185                     else if (requestType == "DELETE")
186                     {
187                         cout << "\t\t\trequestType : DELETE\n";
188                         // DELETE request operations
189                     }
190                 }
191
192                 if (requestFlag & RequestHandlerFlag::ObserverFlag)
193                 {
194                     cout << "\t\trequestFlag : Observer\n";
195
196                     ObservationInfo observationInfo = request->getObservationInfo();
197                     if (ObserveAction::ObserveRegister == observationInfo.action)
198                     {
199                         m_interestedObservers.push_back(observationInfo.obsId);
200                     }
201                     else if (ObserveAction::ObserveUnregister == observationInfo.action)
202                     {
203                         m_interestedObservers.erase(remove(
204                                                         m_interestedObservers.begin(),
205                                                         m_interestedObservers.end(),
206                                                         observationInfo.obsId),
207                                                     m_interestedObservers.end());
208                     }
209                 }
210             }
211             else
212             {
213                 cout << "Request invalid" << endl;
214             }
215
216             return ehResult;
217         }
218 };
219
220 class TemperatureResource : public Resource //oic.r.temperature
221 {
222     private:
223         int m_temperature;
224         string m_range;
225         string m_units;
226
227     public:
228         TemperatureResource(string uri, vector<string> rt, vector<string> itf)
229             : Resource(uri, rt, itf)
230         {
231             m_temperature = 0;
232             m_range = "";
233             m_units = "";
234             m_representation.setValue("temperature", m_temperature);
235             m_representation.setValue("range", m_range);
236             m_representation.setValue("units", m_units);
237         }
238
239         void setTemperatureRepresentation(OCRepresentation &rep)
240         {
241             int temperature;
242             string range;
243             int units;
244
245             if (rep.getValue("temperature", temperature) &&
246                 rep.getValue("range", range) &&
247                 rep.getValue("units", units))
248             {
249                 m_temperature = temperature;
250                 m_range = range;
251                 m_units = units;
252                 m_representation.setValue("temperature", m_temperature);
253                 m_representation.setValue("range", m_range);
254                 m_representation.setValue("units", m_units);
255                 cout << "\t\t\t\t" << "temperature: " << m_temperature << endl;
256                 cout << "\t\t\t\t" << "range: " << m_range << endl;
257                 cout << "\t\t\t\t" << "units: " << m_units << endl;
258
259                 propagate();
260             }
261         }
262
263         OCEntityHandlerResult entityHandler(shared_ptr<OCResourceRequest> request)
264         {
265             cout << "\tIn Server Temperature entity handler:\n";
266             OCEntityHandlerResult ehResult = OC_EH_ERROR;
267
268             if (request)
269             {
270                 // Get the request type and request flag
271                 string requestType = request->getRequestType();
272                 int requestFlag = request->getRequestHandlerFlag();
273
274                 if (requestFlag & RequestHandlerFlag::RequestFlag)
275                 {
276                     cout << "\t\trequestFlag : Request\n";
277
278                     // If the request type is GET
279                     if (requestType == "GET")
280                     {
281                         cout << "\t\t\trequestType : GET\n";
282                         if (OC_STACK_OK == sendRepresentation(request))
283                         {
284                             ehResult = OC_EH_OK;
285                         }
286                     }
287                     else if (requestType == "PUT")
288                     {
289                         cout << "\t\t\trequestType : PUT\n";
290                         // PUT requeist operations
291                     }
292                     else if (requestType == "POST")
293                     {
294                         cout << "\t\t\trequestType : POST\n";
295                         // POST request operations
296                         OCRepresentation    rep = request->getResourceRepresentation();
297                         setTemperatureRepresentation(rep);
298
299                         if (OC_STACK_OK == sendRepresentation(request))
300                         {
301                             ehResult = OC_EH_OK;
302                         }
303                     }
304                     else if (requestType == "DELETE")
305                     {
306                         cout << "\t\t\trequestType : DELETE\n";
307                         // DELETE request operations
308                     }
309                 }
310
311                 if (requestFlag & RequestHandlerFlag::ObserverFlag)
312                 {
313                     cout << "\t\trequestFlag : Observer\n";
314
315                     ObservationInfo observationInfo = request->getObservationInfo();
316                     if (ObserveAction::ObserveRegister == observationInfo.action)
317                     {
318                         m_interestedObservers.push_back(observationInfo.obsId);
319                     }
320                     else if (ObserveAction::ObserveUnregister == observationInfo.action)
321                     {
322                         m_interestedObservers.erase(remove(
323                                                         m_interestedObservers.begin(),
324                                                         m_interestedObservers.end(),
325                                                         observationInfo.obsId),
326                                                     m_interestedObservers.end());
327                     }
328                 }
329             }
330             else
331             {
332                 cout << "Request invalid" << endl;
333             }
334
335             return ehResult;
336         }
337 };
338
339 class AirConditionerResource : public Resource // oic.d.airconditioner
340 {
341     private:
342
343     public:
344         AirConditionerResource(string uri, vector<string> rt, vector<string> itf)
345             : Resource(uri, rt, itf)
346         {
347
348         }
349
350         OCEntityHandlerResult entityHandler(shared_ptr<OCResourceRequest> request)
351         {
352             cout << "\tIn Server Airconditioner entity handler:\n";
353             OCEntityHandlerResult ehResult = OC_EH_ERROR;
354
355             if (request)
356             {
357                 // Get the request type and request flag
358                 string requestType = request->getRequestType();
359                 int requestFlag = request->getRequestHandlerFlag();
360
361                 if (requestFlag & RequestHandlerFlag::RequestFlag)
362                 {
363                     cout << "\t\trequestFlag : Request\n";
364
365                     // If the request type is GET
366                     if (requestType == "GET")
367                     {
368                         cout << "\t\t\trequestType : GET\n";
369                         string findRes = request->getQueryParameters().find("if")->second;
370                         if (findRes.compare(LINK_INTERFACE) == 0)
371                         {
372                             if (OC_STACK_OK == sendRepresentation(request))
373                             {
374                                 ehResult = OC_EH_OK;
375                             }
376                         }
377                         else
378                         {
379                             ehResult = OC_EH_FORBIDDEN;
380                         }
381                     }
382                     else if (requestType == "PUT")
383                     {
384                         cout << "\t\t\trequestType : PUT\n";
385                         // Call these functions to prepare the response for child resources and
386                         // then send the final response using sendRoomResponse function
387
388                         /*
389                         for (auto it = m_childResources.begin();
390                              it != m_childResources.end(); it++)
391                         {
392                             (*it)->entityHandler(request);
393                         }
394
395                         if (OC_STACK_OK == sendRepresentation(request))
396                         {
397                             ehResult = OC_EH_OK;
398                         }
399                         */
400                     }
401                     else if (requestType == "POST")
402                     {
403                         // POST request operations
404                     }
405                     else if (requestType == "DELETE")
406                     {
407                         // DELETE request operations
408                     }
409                 }
410
411                 if (requestFlag & RequestHandlerFlag::ObserverFlag)
412                 {
413                     cout << "\t\trequestFlag : Observer\n";
414                 }
415             }
416             else
417             {
418                 cout << "Request invalid" << endl;
419             }
420
421             return ehResult;
422         }
423 };
424
425 condition_variable g_callbackLock;
426 string             g_uid;
427 string             g_accesstoken;
428
429 void onPublish(const OCRepresentation &, const int &eCode)
430 {
431     cout << "Publish resource response received, code: " << eCode << endl;
432
433     g_callbackLock.notify_all();
434 }
435
436 void printRepresentation(OCRepresentation rep)
437 {
438     for (auto itr = rep.begin(); itr != rep.end(); ++itr)
439     {
440         cout << "\t" << itr->attrname() << ":\t" << itr->getValueToString() << endl;
441         if (itr->type() == AttributeType::Vector)
442         {
443             switch (itr->base_type())
444             {
445                 case AttributeType::OCRepresentation:
446                     for (auto itr2 : (*itr).getValue<vector<OCRepresentation> >())
447                     {
448                         printRepresentation(itr2);
449                     }
450                     break;
451
452                 case AttributeType::Integer:
453                     for (auto itr2 : (*itr).getValue<vector<int> >())
454                     {
455                         cout << "\t\t" << itr2 << endl;
456                     }
457                     break;
458
459                 case AttributeType::String:
460                     for (auto itr2 : (*itr).getValue<vector<string> >())
461                     {
462                         cout << "\t\t" << itr2 << endl;
463                     }
464                     break;
465
466                 default:
467                     cout << "Unhandled base type " << itr->base_type() << endl;
468                     break;
469             }
470         }
471         else if (itr->type() == AttributeType::OCRepresentation)
472         {
473             printRepresentation((*itr).getValue<OCRepresentation>());
474         }
475     }
476 }
477
478 void handleLoginoutCB(const HeaderOptions &,
479                       const OCRepresentation &rep, const int ecode)
480 {
481     cout << "Auth response received code: " << ecode << endl;
482
483     if (rep.getPayload() != NULL)
484     {
485         printRepresentation(rep);
486     }
487
488     if (ecode == 4)
489     {
490         g_accesstoken = rep.getValueToString("accesstoken");
491
492         g_uid = rep.getValueToString("uid");
493     }
494
495     g_callbackLock.notify_all();
496 }
497
498 static FILE *client_open(const char * /*path*/, const char *mode)
499 {
500     return fopen("./aircon_controlee.dat", mode);
501 }
502
503 int main(int argc, char *argv[])
504 {
505     if (argc != 4 && argc != 5)
506     {
507         cout << "Put \"[host-ipaddress:port] [authprovider] [authcode]\" for sign-up and sign-in and publish resources"
508              << endl;
509         cout << "Put \"[host-ipaddress:port] [uid] [accessToken] 1\" for sign-in and publish resources" <<
510              endl;
511         return 0;
512     }
513
514     OCPersistentStorage ps{ client_open, fread, fwrite, fclose, unlink };
515
516     PlatformConfig cfg
517     {
518         ServiceType::InProc,
519         ModeType::Both,
520         "0.0.0.0", // By setting to "0.0.0.0", it binds to all available interfaces
521         0,         // Uses randomly available port
522         QualityOfService::LowQos,
523         &ps
524     };
525
526     OCPlatform::Configure(cfg);
527
528     OCStackResult result = OC_STACK_ERROR;
529
530     string host = "coap+tcp://";
531     host += argv[1];
532
533     OCAccountManager::Ptr accountMgr = OCPlatform::constructAccountManagerObject(host,
534                                        CT_ADAPTER_TCP);
535
536     mutex blocker;
537     unique_lock<mutex> lock(blocker);
538
539     if (argc == 5)
540     {
541         accountMgr->signIn(argv[2], argv[3], &handleLoginoutCB);
542         g_callbackLock.wait(lock);
543     }
544     else
545     {
546         accountMgr->signUp(argv[2], argv[3], &handleLoginoutCB);
547         g_callbackLock.wait(lock);
548         accountMgr->signIn(g_uid, g_accesstoken, &handleLoginoutCB);
549         g_callbackLock.wait(lock);
550     }
551
552
553     cout << "Registering resources to platform..." << endl;
554
555     AirConditionerResource  airConditioner("/sec/aircon/0", { "x.com.samsung.da.device" }, { DEFAULT_INTERFACE, BATCH_INTERFACE, LINK_INTERFACE });
556
557     BinarySwitchResource    binarySwitch("/power/0", { "oic.r.switch.binary" }, { DEFAULT_INTERFACE });
558
559     TemperatureResource     temperature("/temperature/0", { "oic.r.temperature" }, { DEFAULT_INTERFACE });
560
561     string uri = airConditioner.getResourceUri();
562     string rt = airConditioner.getResourceType()[0];
563     string itf = airConditioner.getInterfaces()[0];
564
565     result = OCPlatform::registerResource(airConditioner.m_handle,
566                                           uri,
567                                           rt,
568                                           itf,
569                                           bind(&AirConditionerResource::entityHandler
570                                                   , &airConditioner, placeholders::_1),
571                                           OC_DISCOVERABLE);
572
573     if (result != OC_STACK_OK)
574     {
575         cout << "Resource registration was unsuccessful" << endl;
576     }
577
578
579     itf = airConditioner.getInterfaces()[1];
580     result = OCPlatform::bindInterfaceToResource(airConditioner.m_handle, itf);
581
582     if (result != OC_STACK_OK)
583     {
584         cout << "Binding second interface was unsuccessful" << endl;
585     }
586
587
588     itf = airConditioner.getInterfaces()[2];
589     result = OCPlatform::bindInterfaceToResource(airConditioner.m_handle, itf);
590
591     if (result != OC_STACK_OK)
592     {
593         cout << "Binding third interface was unsuccessful" << endl;
594     }
595
596
597     uri = binarySwitch.getResourceUri();
598     rt = binarySwitch.getResourceType()[0];
599     itf = binarySwitch.getInterfaces()[0];
600
601     result = OCPlatform::registerResource(binarySwitch.m_handle,
602                                           uri,
603                                           rt,
604                                           itf,
605                                           bind(&BinarySwitchResource::entityHandler
606                                                   , &binarySwitch, placeholders::_1),
607                                           OC_OBSERVABLE);
608
609     uri = temperature.getResourceUri();
610     rt = temperature.getResourceType()[0];
611     itf = temperature.getInterfaces()[0];
612
613     result = OCPlatform::registerResource(temperature.m_handle,
614                                           uri,
615                                           rt,
616                                           itf,
617                                           bind(&TemperatureResource::entityHandler
618                                                   , &temperature, placeholders::_1),
619                                           OC_OBSERVABLE);
620
621     result = airConditioner.addChildResource(&binarySwitch);
622
623     result = airConditioner.addChildResource(&temperature);
624
625     cout << "Publishing resources to cloud ";
626
627
628     ResourceHandles resourceHandles;
629
630     OCDeviceInfo        devInfoAirConditioner;
631     OCStringLL          deviceType;
632
633     deviceType.value = "oic.d.airconditioner";
634     deviceType.next = NULL;
635     devInfoAirConditioner.deviceName = "FAC_2016";
636     devInfoAirConditioner.types = &deviceType;
637     devInfoAirConditioner.specVersion = NULL;
638     devInfoAirConditioner.dataModelVersions = NULL;
639
640     OCPlatform::registerDeviceInfo(devInfoAirConditioner);
641
642     result = RDClient::Instance().publishResourceToRD(host, OCConnectivityType::CT_ADAPTER_TCP,
643              resourceHandles,
644              &onPublish);
645
646     cout << " result: " << result << " Waiting Publish default resource response from cloud" << endl;
647
648     resourceHandles.push_back(airConditioner.m_handle);
649
650     result = RDClient::Instance().publishResourceToRD(host, OCConnectivityType::CT_ADAPTER_TCP,
651              resourceHandles,
652              &onPublish);
653
654     cout << " result: " << result << " Waiting Publish user resource response from cloud" << endl;
655
656     g_callbackLock.wait(lock);
657
658
659     cout << "PUT 1/0 to turn on/off air conditioner for observe testing, q to terminate" << endl;
660
661     string cmd;
662
663     while (true)
664     {
665         cin >> cmd;
666         OCRepresentation    rep;
667
668         switch (cmd[0])
669         {
670             case '1':
671                 rep.setValue(string("value"), true);
672                 binarySwitch.setBinarySwitchRepresentation(rep);
673                 break;
674
675             case '0':
676                 rep.setValue(string("value"), false);
677                 binarySwitch.setBinarySwitchRepresentation(rep);
678                 break;
679
680             case 'q':
681                 goto exit;
682         }
683     }
684
685 exit:
686     return 0;
687 }