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 #include "SinricProId.h"
14 
15 #include <map>
16 
24 class SinricProDevice : public SinricProDeviceInterface {
25  public:
26  SinricProDevice(const DeviceId &deviceId);
27  virtual ~SinricProDevice();
28  virtual DeviceId getDeviceId();
29  virtual String getProductType();
30  virtual void begin(SinricProInterface* eventSender);
31 
32  // callback definitions
46  typedef std::function<bool(const String&, bool&)> PowerStateCallback;
47 
48 
49  // standard request handler
50  virtual bool handleRequest(const DeviceId &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 DeviceId &deviceId, const char* action, const char* cause);
61  unsigned long getTimestamp();
62  DeviceId deviceId;
63  PowerStateCallback powerStateCallback;
64  template <typename T>
65  T limitValue(T value, T minValue, T maxValue);
66  private:
67  SinricProInterface* eventSender;
68  std::map<String, LeakyBucket_t> eventFilter;
69 };
70 
71 SinricProDevice::SinricProDevice(const DeviceId &deviceId) :
72  deviceId(deviceId),
73  powerStateCallback(nullptr),
74  eventSender(nullptr) {
75 }
76 
77 SinricProDevice::~SinricProDevice() {
78 }
79 
80 void SinricProDevice::begin(SinricProInterface* eventSender) {
81  this->eventSender = eventSender;
82 }
83 
84 DeviceId SinricProDevice::getDeviceId() {
85  return deviceId;
86 }
87 
88 bool SinricProDevice::handleRequest(const DeviceId &deviceId, const char* action, JsonObject &request_value, JsonObject &response_value) {
89  if (deviceId != this->deviceId) return false;
90  DEBUG_SINRIC("SinricProDevice::handleRequest()\r\n");
91  bool success = false;
92  String actionString = String(action);
93 
94  if (actionString == "setPowerState" && powerStateCallback) {
95  bool powerState = request_value["state"]=="On"?true:false;
96  success = powerStateCallback(deviceId, powerState);
97  response_value["state"] = powerState?"On":"Off";
98  return success;
99  }
100  return success;
101 }
102 
103 DynamicJsonDocument SinricProDevice::prepareEvent(const DeviceId &deviceId, const char* action, const char* cause) {
104  if (eventSender) return eventSender->prepareEvent(deviceId, action, cause);
105  DEBUG_SINRIC("[SinricProDevice:prepareEvent()]: Device \"%s\" isn't configured correctly! The \'%s\' event will be ignored.\r\n", deviceId.toString().c_str(), action);
106  return DynamicJsonDocument(1024);
107 }
108 
109 
110 bool SinricProDevice::sendEvent(JsonDocument& event) {
111  if (!eventSender) return false;
112  if (!eventSender->isConnected()) {
113  DEBUG_SINRIC("[SinricProDevice::sendEvent]: The event could not be sent. No connection to the SinricPro server.\r\n");
114  return false;
115  }
116  String eventName = event["payload"]["action"] | ""; // get event name
117 
118  LeakyBucket_t bucket; // leaky bucket algorithm is used to prevent flooding the server
119 
120  // get leaky bucket for event from eventFilter
121  if (eventFilter.find(eventName) == eventFilter.end()) { // if there is no bucket ...
122  eventFilter[eventName] = bucket; // ...add a new bucket
123  } else {
124  bucket = eventFilter[eventName]; // else get bucket
125  }
126 
127  if (bucket.addDrop()) { // if we can add a new drop
128  eventSender->sendMessage(event); // send event
129  eventFilter[eventName] = bucket; // update bucket on eventFilter
130  return true;
131  }
132 
133  eventFilter[eventName] = bucket; // update bucket on eventFilter
134  return false;
135 }
136 
137 unsigned long SinricProDevice::getTimestamp() {
138  if (eventSender) return eventSender->getTimestamp();
139  return 0;
140 }
141 
142 template <typename T>
143 T SinricProDevice::limitValue(T value, T minValue, T maxValue) {
144  T newValue = value;
145  if (value > maxValue) newValue = maxValue;
146  if (value < minValue) newValue = minValue;
147  return newValue;
148 }
149 
158  powerStateCallback = cb;
159 }
160 
170 bool SinricProDevice::sendPowerStateEvent(bool state, String cause) {
171  DynamicJsonDocument eventMessage = prepareEvent(deviceId, "setPowerState", cause.c_str());
172  JsonObject event_value = eventMessage["payload"]["value"];
173  event_value["state"] = state?"On":"Off";
174  return sendEvent(eventMessage);
175 }
176 
177 String SinricProDevice::getProductType() {
178  return String("sinric.device.type.");
179 }
180 
181 #endif
SinricProDevice::sendPowerStateEvent
bool sendPowerStateEvent(bool state, String cause="PHYSICAL_INTERACTION")
Send setPowerState event to SinricPro Server indicating actual power state.
Definition: SinricProDevice.h:170
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:24
SinricProDevice::onPowerState
virtual void onPowerState(PowerStateCallback cb)
Set callback function for powerState request.
Definition: SinricProDevice.h:157