Skip to content

Commit 1efa746

Browse files
committed
Merge branch 'dev'
2 parents e050652 + 5c9e96b commit 1efa746

7 files changed

+148
-58
lines changed

README.md

+9-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11

22
# SinricPro (ESP8266 / ESP32 SDK)
3-
## Version 2.2.0
3+
## Version 2.2.1
44
## Installation
55

66
### VS Code & PlatformIO:
@@ -9,15 +9,15 @@
99
3. Install **SinricPro** library by using [Library Manager](https://docs.platformio.org/en/latest/librarymanager/)
1010
4. Use included [platformio.ini](https://github.com/sinricpro/esp8266-esp32-sdk/blob/master/pio-examples/switch/platformio.ini) files from [examples](https://github.com/sinricpro/esp8266-esp32-sdk/tree/master/pio-examples) to ensure that all dependent libraries will installed automaticly.
1111

12-
![sinricpro library manager](https://github.com/sinricpro/images/blob/master/platformio-install-sinricpro.png)
12+
![sinricpro library manager](https://raw.githubusercontent.com/sinricpro/images/master/platformio-install-sinricpro.png)
1313

1414
### ArduinoIDE
1515
1. Open Library Manager (*Tools / Manage Libraries*)
1616
2. Search for *SinricPro* and click *Install*
1717
3. Repeat step 2 for all [dependent libraries](#dependencies)!
1818
4. Open example in ArduinoIDE (*File / Examples / SinricPro / ...*)
1919

20-
![ArduinoIDE Library Manager](https://github.com/sinricpro/images/blob/master/ArduinoIDE-Library-Manager.png)
20+
![ArduinoIDE Library Manager](https://raw.githubusercontent.com/sinricpro/images/master/ArduinoIDE-Library-Manager.png)
2121

2222
---
2323

@@ -74,9 +74,13 @@ bool onPowerState(const String deviceId, bool &state) {
7474
## How to add a device?
7575
Syntax is
7676
```C++
77-
DeviceType& myDevice = SinricPro.add<DeviceType>(DEVICE_ID);
77+
DeviceType& myDevice = SinricPro[DEVICE_ID];
7878
```
7979
Example
80+
```C++
81+
SinricProSwitch& mySwitch = SinricPro["YOUR-SWITCH-ID-HERE"];
82+
```
83+
*Example 2 (alternatively)*
8084
```C++
8185
SinricProSwitch& mySwitch = SinricPro.add<SinricProSwitch>("YOUR-SWITCH-ID-HERE");
8286
```
@@ -93,7 +97,7 @@ Example 1
9397
myDoorbell.sendDoorbellEvent();
9498
```
9599

96-
Example 2 (alternatively)
100+
*Example 2 (alternatively)*
97101
```C++
98102
SinricPro["YOUR-DOORBELL-ID-HERE"].as<SinricProDoorbell>().sendDoorbellEvent();
99103
```

library.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"maintainer": true
1414
}
1515
],
16-
"version": "2.2.0",
16+
"version": "2.2.1",
1717
"frameworks": "arduino",
1818
"platforms": [
1919
"espressif8266",

library.properties

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name=SinricPro
2-
version=2.2.0
2+
version=2.2.1
33
author=Boris Jaeger <[email protected]>
44
maintainer=Boris Jaeger <[email protected]>
55
sentence=Library for https://sinric.pro - simple way to connect your device to alexa
@@ -8,4 +8,4 @@ category=Communication
88
url=https:://sinric.pro
99
architectures=esp8266,esp32
1010
repository=https://github.com/sinricpro/esp8266-esp32-sdk.git
11-
license=CC-BY-SA
11+
license=CC-BY-SA

src/SinricPro.h

+101-32
Original file line numberDiff line numberDiff line change
@@ -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

8695
SinricProDeviceInterface* 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+
93118
void 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

99141
template <typename DeviceType>
100142
DeviceType& 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);")))
110156
void 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);")))
117163
void 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

123169
void 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

270336
void 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+
296365
void SinricProClass::extractTimestamp(JsonDocument &message) {
297366
unsigned long tempTimestamp = 0;
298367
// extract timestamp from timestamp message right after websocket connection is established

src/SinricProConfig.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
#ifndef __SINRICPRO_CONFIG_H__
99
#define __SINRICPRO_CONFIG_H__
1010

11-
#define SDK_VERSION "2.2.0"
11+
#define SDK_VERSION "2.2.1"
1212

1313
#define SINRICPRO_SERVER_URL "ws.sinric.pro"
1414
#define SINRICPRO_SERVER_PORT 80

src/SinricProDevice.h

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ const char* SinricProDevice::getDeviceId() {
4949

5050
DynamicJsonDocument SinricProDevice::prepareEvent(const char* deviceId, const char* action, const char* cause) {
5151
if (eventSender) return eventSender->prepareEvent(deviceId, action, cause);
52+
DEBUG_SINRIC("[SinricProDevice:prepareEvent()]: Device \"%s\" isn't configured correctly! The \'%s\' event will be ignored.\r\n", deviceId, action);
5253
return DynamicJsonDocument(1024);
5354
}
5455

0 commit comments

Comments
 (0)