@@ -27,6 +27,11 @@ class SinricProClass : public SinricProInterface {
2727 void handle ();
2828 void stop ();
2929 bool isConnected ();
30+
31+ typedef std::function<void (void )> connectCallbackHandler;
32+ void onConnected (connectCallbackHandler cb) { _websocketListener.onConnected (cb); }
33+ void onDisconnected (connectCallbackHandler cb) { _websocketListener.onDisconnected (cb); }
34+
3035 void restoreDeviceStates (bool flag) { _websocketListener.setRestoreDeviceStates (flag); }
3136
3237 DynamicJsonDocument prepareResponse (JsonDocument& requestMessage);
@@ -58,16 +63,18 @@ class SinricProClass : public SinricProInterface {
5863 void disconnect ();
5964 void reconnect ();
6065
61- void onConnect () { DEBUG_SINRIC (" [SinricPro:onConnect() ]\r\n " ); }
62- void onDisconnect () { DEBUG_SINRIC (" [SinricPro:onDisconnect()] \r\n " ); }
66+ void onConnect () { DEBUG_SINRIC (" [SinricPro]: Connected to \" %s \" ! ]\r\n " , serverURL. c_str () ); }
67+ void onDisconnect () { DEBUG_SINRIC (" [SinricPro]: Disconnect \r\n " ); }
6368
64- bool checkDeviceId (String deviceId);
69+ bool verifyDeviceId (const char * id);
70+ bool verifyAppKey (const char * key);
71+ bool verifyAppSecret (const char * secret);
6572 void extractTimestamp (JsonDocument &message);
6673
6774 SinricProDeviceInterface* getDevice (String deviceId);
6875
6976 template <typename DeviceType>
70- DeviceType& getDeviceInstance (String deviceId) { return (DeviceType&) * getDevice (deviceId); }
77+ DeviceType& getDeviceInstance (String deviceId);
7178
7279 std::vector<SinricProDeviceInterface*> devices;
7380 String socketAuthToken;
@@ -81,6 +88,8 @@ class SinricProClass : public SinricProInterface {
8188
8289 unsigned long getTimestamp () { return baseTimestamp + (millis ()/1000 ); }
8390 unsigned long baseTimestamp = 0 ;
91+
92+ bool _begin = false ;
8493};
8594
8695SinricProDeviceInterface* SinricProClass::getDevice (String deviceId) {
@@ -90,37 +99,86 @@ SinricProDeviceInterface* SinricProClass::getDevice(String deviceId) {
9099 return nullptr ;
91100}
92101
102+ template <typename DeviceType>
103+ DeviceType& SinricProClass::getDeviceInstance (String deviceId) {
104+ DeviceType* tmp_device = (DeviceType*) getDevice (deviceId);
105+ if (tmp_device) return *tmp_device;
106+
107+ DEBUG_SINRIC (" [SinricPro]: Device \" %s\" does not exist. Creating new device\r\n " , deviceId.c_str ());
108+ DeviceType& tmp_deviceInstance = add<DeviceType>(deviceId.c_str ());
109+
110+ if (isConnected ()) {
111+ DEBUG_SINRIC (" [SinricPro]: Reconnecting to server.\r\n " );
112+ reconnect ();
113+ }
114+
115+ return tmp_deviceInstance;
116+ }
117+
93118void SinricProClass::begin (String socketAuthToken, String signingKey, String serverURL) {
119+ bool success = true ;
120+ if (!verifyAppKey (socketAuthToken.c_str ())) {
121+ DEBUG_SINRIC (" [SinricPro:begin()]: App-Key \" %s\" is invalid!! Please check your app-key!! SinricPro will not work!\r\n " , socketAuthToken.c_str ());
122+ success = false ;
123+ }
124+ if (!verifyAppSecret (signingKey.c_str ())) {
125+ DEBUG_SINRIC (" [SinricPro:begin()]: App-Secret \" %s\" is invalid!! Please check your app-secret!! SinricPro will not work!\r\n " , signingKey.c_str ());
126+ success = false ;
127+ return ;
128+ }
129+
130+ if (!success) {
131+ _begin = false ;
132+ return ;
133+ }
134+
94135 this ->socketAuthToken = socketAuthToken;
95136 this ->signingKey = signingKey;
96137 this ->serverURL = serverURL;
138+ _begin = true ;
97139}
98140
99141template <typename DeviceType>
100142DeviceType& SinricProClass::add (const char * deviceId, unsigned long eventWaitTime) {
101143 DeviceType* newDevice = new DeviceType (deviceId, eventWaitTime);
102- if (checkDeviceId (String (deviceId))){
144+ if (verifyDeviceId (deviceId)){
145+ DEBUG_SINRIC (" [SinricPro:add()]: Adding device with id \" %s\" .\r\n " , deviceId);
103146 newDevice->begin (this );
104- devices.push_back (newDevice);
147+ if (verifyAppKey (socketAuthToken.c_str ()) && verifyAppSecret (signingKey.c_str ())) _begin = true ;
148+ } else {
149+ DEBUG_SINRIC (" [SinricPro:add()]: DeviceId \" %s\" is invalid!! Device will be ignored and will NOT WORK!\r\n " , deviceId);
105150 }
151+ devices.push_back (newDevice);
106152 return *newDevice;
107153}
108154
109155__attribute__ ((deprecated(" Please use DeviceType& myDevice = SinricPro.add<DeviceType>(DeviceId);" )))
110156void SinricProClass::add(SinricProDeviceInterface* newDevice) {
111- if (!checkDeviceId ( String ( newDevice->getDeviceId () ))) return ;
157+ if (!verifyDeviceId ( newDevice->getDeviceId ())) return ;
112158 newDevice->begin (this );
113159 devices.push_back (newDevice);
114160}
115161
116162__attribute__ ((deprecated(" Please use DeviceType& myDevice = SinricPro.add<DeviceType>(DeviceId);" )))
117163void SinricProClass::add(SinricProDeviceInterface& newDevice) {
118- if (!checkDeviceId ( String ( newDevice.getDeviceId () ))) return ;
164+ if (!verifyDeviceId ( newDevice.getDeviceId ())) return ;
119165 newDevice.begin (this );
120166 devices.push_back (&newDevice);
121167}
122168
123169void SinricProClass::handle () {
170+ static bool begin_error = false ;
171+ if (!_begin) {
172+ if (!begin_error) { // print this only once!
173+ DEBUG_SINRIC (" [SinricPro:handle()]: ERROR! SinricPro.begin() failed or was not called prior to event handler\r\n " );
174+ DEBUG_SINRIC (" [SinricPro:handle()]: -Reasons include an invalid app-key, invalid app-secret or no valid deviceIds)\r\n " );
175+ DEBUG_SINRIC (" [SinricPro:handle()]: -SinricPro is disabled! Check earlier log messages for details.\r\n " );
176+ begin_error = true ;
177+ }
178+ return ;
179+ }
180+
181+
124182 if (!isConnected ()) connect ();
125183 _websocketListener.handle ();
126184 _udpListener.handle ();
@@ -201,12 +259,12 @@ void SinricProClass::handleReceiveQueue() {
201259 String messageType = jsonMessage[" payload" ][" type" ];
202260
203261 if (sigMatch) { // signature is valid process message
204- DEBUG_SINRIC (" [SinricPro.handleReceiveQueue()]: Signature is valid! Processing message.\r\n " );
262+ DEBUG_SINRIC (" [SinricPro.handleReceiveQueue()]: Signature is valid. Processing message.. .\r\n " );
205263 extractTimestamp (jsonMessage);
206264 if (messageType == " response" ) handleResponse (jsonMessage);
207265 if (messageType == " request" ) handleRequest (jsonMessage, rawMessage->getInterface ());
208266 } else {
209- DEBUG_SINRIC (" [SinricPro.handleReceiveQueue()]: Signature is invalid...sending messsage to [dev/null] ;)\r\n " );
267+ DEBUG_SINRIC (" [SinricPro.handleReceiveQueue()]: Signature is invalid! Sending messsage to [dev/null] ;)\r\n " );
210268 }
211269 delete rawMessage;
212270 }
@@ -248,12 +306,20 @@ void SinricProClass::connect() {
248306 String deviceList;
249307 int i = 0 ;
250308 for (auto & device : devices) {
251- if (i>0 ) deviceList += " ;" ;
252- deviceList += String (device->getDeviceId ());
253- i++;
309+ const char * deviceId = device->getDeviceId ();
310+ if (verifyDeviceId (deviceId)) {
311+ if (i>0 ) deviceList += ' ;' ;
312+ deviceList += String (deviceId);
313+ i++;
314+ }
315+ }
316+ if (i==0 ) { // no device have been added! -> do not connect!
317+ _begin = false ;
318+ DEBUG_SINRIC (" [SinricPro]: ERROR! No valid devices available. Please add a valid device first!\r\n " );
319+ return ;
254320 }
255321
256- _websocketListener.begin (serverURL, socketAuthToken, deviceList. c_str () , &receiveQueue);
322+ _websocketListener.begin (serverURL, socketAuthToken, deviceList, &receiveQueue);
257323}
258324
259325
@@ -268,31 +334,34 @@ bool SinricProClass::isConnected() {
268334
269335
270336void SinricProClass::reconnect () {
271- DEBUG_SINRIC (" SinricProClass. reconnect(): disconnecting\r\n " );
337+ DEBUG_SINRIC (" SinricPro: reconnect(): disconnecting\r\n " );
272338 stop ();
273- DEBUG_SINRIC (" SinricProClass.reconnect(): wait 1second\r\n " );
274- delay (1000 );
275- DEBUG_SINRIC (" SinricProClass.reconnect(): connecting\r\n " );
339+ DEBUG_SINRIC (" SinricPro:reconnect(): connecting\r\n " );
276340 connect ();
277341}
278342
279- bool SinricProClass::checkDeviceId (String deviceId) {
280- if (deviceId.length () != 24 ) {
281- DEBUG_SINRIC (" [SinricPro.add()]: Invalid deviceId \" %s\" ! Device will be ignored!\r\n " , deviceId.c_str ());
282- return false ;
283- }
343+ bool SinricProClass::verifyDeviceId (const char * id) {
344+ if (strlen (id) != 24 ) return false ;
345+ int tmp; char tmp_c;
346+ return sscanf (id, " %4x%4x%4x%4x%4x%4x%c" ,
347+ &tmp, &tmp, &tmp, &tmp, &tmp, &tmp, &tmp_c) == 6 ;
348+ }
284349
285- for (size_t i = 0 ; i < deviceId.length (); i++) {
286- char current = deviceId[i];
287- if (current >= ' 0' && current <= ' 9' ) continue ;
288- if (current >= ' A' && current <= ' F' ) continue ;
289- if (current >= ' a' && current <= ' f' ) continue ;
290- DEBUG_SINRIC (" [SinricPro.add()]: Invalid deviceId \" %s\" ! Device will be ignored!\r\n " , deviceId.c_str ());
291- return false ;
292- }
293- return true ;
350+ bool SinricProClass::verifyAppKey (const char * key) {
351+ if (strlen (key) != 36 ) return false ;
352+ int tmp; char tmp_c;
353+ return sscanf (key, " %4x%4x-%4x-%4x-%4x-%4x%4x%4x%c" ,
354+ &tmp, &tmp, &tmp, &tmp, &tmp, &tmp, &tmp, &tmp, &tmp_c) == 8 ;
294355}
295356
357+ bool SinricProClass::verifyAppSecret (const char * secret) {
358+ if (strlen (secret) != 73 ) return false ;
359+ int tmp; char tmp_c;
360+ return sscanf (secret, " %4x%4x-%4x-%4x-%4x-%4x%4x%4x-%4x%4x-%4x-%4x-%4x-%4x%4x%4x%c" ,
361+ &tmp, &tmp, &tmp, &tmp, &tmp, &tmp, &tmp, &tmp, &tmp, &tmp, &tmp, &tmp, &tmp, &tmp, &tmp, &tmp, &tmp_c) == 16 ;
362+ }
363+
364+
296365void SinricProClass::extractTimestamp (JsonDocument &message) {
297366 unsigned long tempTimestamp = 0 ;
298367 // extract timestamp from timestamp message right after websocket connection is established
0 commit comments