SinricPro Library
SinricProDevice.h
1 /*
2  * Copyright (c) 2019 Sinric. All rights reserved.
3  * Licensed under Creative Commons Attribution-Share Alike (CC BY-SA)
4  *
5  * This file is part of the Sinric Pro (https://github.com/sinricpro/)
6  */
7 
8 #ifndef _SINRICDEVICE_H_
9 #define _SINRICDEVICE_H_
10 
11 #include "SinricProDeviceInterface.h"
12 #include "LeakyBucket.h"
13 
14 #include <map>
15 
23 class SinricProDevice : public SinricProDeviceInterface {
24  public:
25  SinricProDevice(const char* newDeviceId, unsigned long eventWaitTime=100);
26  virtual ~SinricProDevice();
27  virtual const char* getDeviceId();
28  virtual String getProductType();
29  virtual void begin(SinricProInterface* eventSender);
30  virtual void setEventWaitTime(unsigned long eventWaitTime) { if (eventWaitTime<100) {this->eventWaitTime=100;} else { this->eventWaitTime=eventWaitTime;} }
31 
32  // callback definitions
46  typedef std::function<bool(const String&, bool&)> PowerStateCallback;
47 
48 
49  // standard request handler
50  virtual bool handleRequest(const char* deviceId, const char* action, JsonObject &request_value, JsonObject &response_value);
51 
52  // standard Callbacks
53  virtual void onPowerState(PowerStateCallback cb);
54 
55  // standard events
56  bool sendPowerStateEvent(bool state, String cause = "PHYSICAL_INTERACTION");
57 
58  protected:
59  virtual bool sendEvent(JsonDocument& event);
60  virtual DynamicJsonDocument prepareEvent(const char* deviceId, const char* action, const char* cause);
61  unsigned long getTimestamp();
62  char* deviceId;
63  PowerStateCallback powerStateCallback;
64  template <typename T>
65  T limitValue(T value, T minValue, T maxValue);
66  private:
67  SinricProInterface* eventSender;
68  unsigned long eventWaitTime;
69  std::map<String, LeakyBucket_t> eventFilter;
70 };
71 
72 SinricProDevice::SinricProDevice(const char* newDeviceId, unsigned long eventWaitTime) :
73  powerStateCallback(nullptr),
74  eventSender(nullptr),
75  eventWaitTime(eventWaitTime) {
76  deviceId = strdup(newDeviceId);
77  if (this->eventWaitTime < 100) this->eventWaitTime = 100;
78 }
79 
80 SinricProDevice::~SinricProDevice() {
81  if (deviceId) free(deviceId);
82 }
83 
84 void SinricProDevice::begin(SinricProInterface* eventSender) {
85  this->eventSender = eventSender;
86 }
87 
88 const char* SinricProDevice::getDeviceId() {
89  return deviceId;
90 }
91 
92 bool SinricProDevice::handleRequest(const char* deviceId, const char* action, JsonObject &request_value, JsonObject &response_value) {
93  if (strcmp(deviceId, this->deviceId) != 0) return false;
94  DEBUG_SINRIC("SinricProDevice::handleRequest()\r\n");
95  bool success = false;
96  String actionString = String(action);
97 
98  if (actionString == "setPowerState" && powerStateCallback) {
99  bool powerState = request_value["state"]=="On"?true:false;
100  success = powerStateCallback(String(deviceId), powerState);
101  response_value["state"] = powerState?"On":"Off";
102  return success;
103  }
104  return success;
105 }
106 
107 DynamicJsonDocument SinricProDevice::prepareEvent(const char* deviceId, const char* action, const char* cause) {
108  if (eventSender) return eventSender->prepareEvent(deviceId, action, cause);
109  DEBUG_SINRIC("[SinricProDevice:prepareEvent()]: Device \"%s\" isn't configured correctly! The \'%s\' event will be ignored.\r\n", deviceId, action);
110  return DynamicJsonDocument(1024);
111 }
112 
113 
114 bool SinricProDevice::sendEvent(JsonDocument& event) {
115  String eventName = event["payload"]["action"] | ""; // get event name
116 
117  LeakyBucket_t bucket; // leaky bucket algorithm is used to prevent flooding the server
118 
119  // get leaky bucket for event from eventFilter
120  if (eventFilter.find(eventName) == eventFilter.end()) { // if there is no bucket ...
121  eventFilter[eventName] = bucket; // ...add a new bucket
122  } else {
123  bucket = eventFilter[eventName]; // else get bucket
124  }
125 
126  if (bucket.addDrop()) { // if we can add a new drop
127  if (eventSender) eventSender->sendMessage(event); // send event
128  eventFilter[eventName] = bucket; // update bucket on eventFilter
129  return true;
130  }
131 
132  eventFilter[eventName] = bucket; // update bucket on eventFilter
133  return false;
134 }
135 
136 unsigned long SinricProDevice::getTimestamp() {
137  if (eventSender) return eventSender->getTimestamp();
138  return 0;
139 }
140 
141 template <typename T>
142 T SinricProDevice::limitValue(T value, T minValue, T maxValue) {
143  T newValue = value;
144  if (value > maxValue) newValue = maxValue;
145  if (value < minValue) newValue = minValue;
146  return newValue;
147 }
148 
157  powerStateCallback = cb;
158 }
159 
169 bool SinricProDevice::sendPowerStateEvent(bool state, String cause) {
170  DynamicJsonDocument eventMessage = prepareEvent(deviceId, "setPowerState", cause.c_str());
171  JsonObject event_value = eventMessage["payload"]["value"];
172  event_value["state"] = state?"On":"Off";
173  return sendEvent(eventMessage);
174 }
175 
176 String SinricProDevice::getProductType() {
177  return String("sinric.device.type.");
178 }
179 
180 #endif
SinricProDevice::sendPowerStateEvent
bool sendPowerStateEvent(bool state, String cause="PHYSICAL_INTERACTION")
Send setPowerState event to SinricPro Server indicating actual power state.
Definition: SinricProDevice.h:169
SinricProDevice::PowerStateCallback
std::function< bool(const String &, bool &)> PowerStateCallback
Callback definition for onPowerState function.
Definition: SinricProDevice.h:46
SinricProDevice
Base class for all device types.
Definition: SinricProDevice.h:23
SinricProDevice::onPowerState
virtual void onPowerState(PowerStateCallback cb)
Set callback function for powerState request.
Definition: SinricProDevice.h:156