SinricPro Library
SinricProWebsocket.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 
9 #ifndef _SINRICPRO_WEBSOCKET_H__
10 #define _SINRICPRO_WEBSOCKET_H__
11 
12 #if defined ESP8266
13  #include <ESP8266WiFi.h>
14 #endif
15 #if defined ESP32
16  #include <WiFi.h>
17 #endif
18 
19 #include <WebSocketsClient.h>
20 #include <ArduinoJson.h>
21 #include "SinricProDebug.h"
22 #include "SinricProConfig.h"
23 #include "SinricProQueue.h"
24 #include "SinricProInterface.h"
25 
26 class websocketListener
27 {
28  public:
29  typedef std::function<void(void)> wsConnectedCallback;
30  typedef std::function<void(void)> wsDisconnectedCallback;
31 
32  websocketListener();
33  ~websocketListener();
34 
35  void begin(String server, String socketAuthToken, String deviceIds, SinricProQueue_t* receiveQueue);
36  void handle();
37  void stop();
38  bool isConnected() { return _isConnected; }
39  void setRestoreDeviceStates(bool flag) { this->restoreDeviceStates = flag; };
40 
41  void sendMessage(String &message);
42 
43  void onConnected(wsConnectedCallback callback) { _wsConnectedCb = callback; }
44  void onDisconnected(wsDisconnectedCallback callback) { _wsDisconnectedCb = callback; }
45 
46  void disconnect() { webSocket.disconnect(); }
47  private:
48  bool _begin = false;
49  bool _isConnected = false;
50  bool restoreDeviceStates = false;
51 
52  WebSocketsClient webSocket;
53 
54  wsConnectedCallback _wsConnectedCb;
55  wsDisconnectedCallback _wsDisconnectedCb;
56 
57  void webSocketEvent(WStype_t type, uint8_t * payload, size_t length);
58  void setExtraHeaders();
59  SinricProQueue_t* receiveQueue;
60  String deviceIds;
61  String socketAuthToken;
62 };
63 
64 void websocketListener::setExtraHeaders() {
65  String headers = "appkey:" + socketAuthToken + "\r\n";
66  headers += "deviceids:" + deviceIds + "\r\n";
67  headers += "restoredevicestates:" + String(restoreDeviceStates?"true":"false") + "\r\n";
68  headers += "ip:" + WiFi.localIP().toString() + "\r\n";
69  headers += "mac:" + WiFi.macAddress() + "\r\n";
70  #ifdef ESP8266
71  headers += "platform:ESP8266\r\n";
72  #endif
73  #ifdef ESP32
74  headers += "platform:ESP32\r\n";
75  #endif
76  headers += "version:" + String(SINRICPRO_VERSION);
77  DEBUG_SINRIC("[SinricPro:Websocket]: headers: \r\n%s\r\n", headers.c_str());
78  webSocket.setExtraHeaders(headers.c_str());
79 }
80 
81 websocketListener::websocketListener() : _isConnected(false) {}
82 
83 websocketListener::~websocketListener() {
84  stop();
85 }
86 
87 void websocketListener::begin(String server, String socketAuthToken, String deviceIds, SinricProQueue_t* receiveQueue) {
88  if (_begin) return;
89  _begin = true;
90 
91  this->receiveQueue = receiveQueue;
92  this->socketAuthToken = socketAuthToken;
93  this->deviceIds = deviceIds;
94 
95 #ifdef WEBSOCKET_SSL
96  DEBUG_SINRIC("[SinricPro:Websocket]: Connecting to WebSocket Server using SSL (%s)\r\n", server.c_str());
97 #else
98  DEBUG_SINRIC("[SinricPro:Websocket]: Connecting to WebSocket Server (%s)\r\n", server.c_str());
99 #endif
100 
101  if (_isConnected) {
102  stop();
103  }
104  setExtraHeaders();
105  webSocket.onEvent([&](WStype_t type, uint8_t * payload, size_t length) { webSocketEvent(type, payload, length); });
106  webSocket.enableHeartbeat(WEBSOCKET_PING_INTERVAL, WEBSOCKET_PING_TIMEOUT, WEBSOCKET_RETRY_COUNT);
107 #ifdef WEBSOCKET_SSL
108  // To get this working, WebSocketsClient.h needs to be fixed. See https://github.com/Links2004/arduinoWebSockets/issues/492
109  webSocket.beginSSL(server, SINRICPRO_SERVER_SSL_PORT, "/");
110 #else
111  webSocket.begin(server, SINRICPRO_SERVER_PORT, "/"); // server address, port and URL
112 #endif
113 }
114 
115 void websocketListener::handle() {
116  webSocket.loop();
117 }
118 
119 void websocketListener::stop() {
120  if (_isConnected) {
121  webSocket.disconnect();
122  }
123  _begin = false;
124 }
125 
126 void websocketListener::sendMessage(String &message) {
127  webSocket.sendTXT(message);
128 }
129 
130 
131 void websocketListener::webSocketEvent(WStype_t type, uint8_t * payload, size_t length)
132 {
133  switch (type) {
134  case WStype_DISCONNECTED:
135  if (_isConnected) {
136  DEBUG_SINRIC("[SinricPro:Websocket]: disconnected\r\n");
137  if (_wsDisconnectedCb) _wsDisconnectedCb();
138  _isConnected = false;
139  }
140  break;
141  case WStype_CONNECTED:
142  _isConnected = true;
143  DEBUG_SINRIC("[SinricPro:Websocket]: connected\r\n");
144  if (_wsConnectedCb) _wsConnectedCb();
145  if (restoreDeviceStates) {
146  restoreDeviceStates=false;
147  setExtraHeaders();
148  }
149  break;
150  case WStype_TEXT: {
151  SinricProMessage* request = new SinricProMessage(IF_WEBSOCKET, (char*)payload);
152  DEBUG_SINRIC("[SinricPro:Websocket]: receiving data\r\n");
153  receiveQueue->push(request);
154  break;
155  }
156  default: break;
157  }
158 }
159 
160 #endif