Skip to content

Commit 3d309d4

Browse files
author
AlphaNodesDev
committed
page issue
1 parent 50e492b commit 3d309d4

File tree

3 files changed

+396
-3
lines changed

3 files changed

+396
-3
lines changed

SciFyIoT.cpp

Lines changed: 299 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,299 @@
1+
#include "SciFyIoT.h"
2+
3+
// Static instance pointer for callback wrapper
4+
SciFyIoT* SciFyIoT::instance = nullptr;
5+
6+
// Constructor
7+
SciFyIoT::SciFyIoT() {
8+
authenticated = false;
9+
lastHeartbeat = 0;
10+
lastActivity = 0;
11+
_commandCallback = nullptr;
12+
_statusCallback = nullptr;
13+
_serverUrl = "api.scify-tech.com";
14+
_serverPort = 443;
15+
_serverPath = "/ws";
16+
17+
// Set static instance for callback wrapper
18+
instance = this;
19+
}
20+
21+
// Initialize with default server
22+
void SciFyIoT::begin(const char* ssid, const char* password, const char* apiKey, const char* secret) {
23+
begin(ssid, password, apiKey, secret, "api.scify-tech.com", 443, "/ws");
24+
}
25+
26+
// Initialize with custom server
27+
void SciFyIoT::begin(const char* ssid, const char* password, const char* apiKey, const char* secret,
28+
const char* serverUrl, int serverPort, const char* serverPath) {
29+
Serial.begin(115200);
30+
delay(1000);
31+
32+
Serial.println("[SciFyIoT] Starting...");
33+
34+
_ssid = ssid;
35+
_password = password;
36+
_apiKey = apiKey;
37+
_secret = secret;
38+
_serverUrl = serverUrl;
39+
_serverPort = serverPort;
40+
_serverPath = serverPath;
41+
42+
pinMode(LED_BUILTIN, OUTPUT);
43+
digitalWrite(LED_BUILTIN, HIGH);
44+
45+
// Connect to WiFi
46+
connectWiFi();
47+
48+
if (WiFi.status() == WL_CONNECTED) {
49+
webSocket.beginSSL(_serverUrl.c_str(), _serverPort, _serverPath.c_str());
50+
webSocket.onEvent(webSocketEventWrapper);
51+
webSocket.setReconnectInterval(5000);
52+
webSocket.enableHeartbeat(15000, 3000, 2);
53+
lastActivity = millis();
54+
Serial.println("[SciFyIoT] Initialized successfully!");
55+
} else {
56+
Serial.println("[SciFyIoT] WiFi connection failed");
57+
}
58+
}
59+
60+
// Main loop processing
61+
void SciFyIoT::loop() {
62+
webSocket.loop();
63+
64+
if (WiFi.status() != WL_CONNECTED) {
65+
connectWiFi();
66+
}
67+
68+
if (authenticated && millis() - lastHeartbeat > heartbeatInterval) {
69+
sendHeartbeat();
70+
lastHeartbeat = millis();
71+
}
72+
73+
checkConnection();
74+
delay(50);
75+
}
76+
77+
// Status methods
78+
bool SciFyIoT::isConnected() {
79+
return webSocket.isConnected();
80+
}
81+
82+
bool SciFyIoT::isAuthenticated() {
83+
return authenticated;
84+
}
85+
86+
bool SciFyIoT::isWiFiConnected() {
87+
return WiFi.status() == WL_CONNECTED;
88+
}
89+
90+
// Connect to WiFi
91+
void SciFyIoT::connectWiFi() {
92+
WiFi.begin(_ssid.c_str(), _password.c_str());
93+
94+
int attempts = 0;
95+
while (WiFi.status() != WL_CONNECTED && attempts < 30) {
96+
delay(500);
97+
attempts++;
98+
}
99+
100+
if (WiFi.status() == WL_CONNECTED) {
101+
Serial.println("[WiFi] Connected");
102+
} else {
103+
Serial.println("[WiFi] Connection failed");
104+
}
105+
}
106+
107+
// Static callback wrapper
108+
void SciFyIoT::webSocketEventWrapper(WStype_t type, uint8_t * payload, size_t length) {
109+
if (instance) {
110+
instance->webSocketEvent(type, payload, length);
111+
}
112+
}
113+
114+
// WebSocket event handler
115+
void SciFyIoT::webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
116+
lastActivity = millis();
117+
118+
switch (type) {
119+
case WStype_DISCONNECTED:
120+
authenticated = false;
121+
digitalWrite(LED_BUILTIN, HIGH);
122+
if (_statusCallback) _statusCallback(false, false);
123+
break;
124+
125+
case WStype_CONNECTED:
126+
authenticated = false;
127+
authenticateDevice();
128+
if (_statusCallback) _statusCallback(true, false);
129+
break;
130+
131+
case WStype_TEXT:
132+
handleWebSocketMessage((char*)payload);
133+
break;
134+
135+
case WStype_ERROR:
136+
Serial.printf("[WS] Error: %s\n", payload);
137+
break;
138+
}
139+
}
140+
141+
// Authenticate with server
142+
void SciFyIoT::authenticateDevice() {
143+
DynamicJsonDocument doc(256);
144+
doc["type"] = "auth";
145+
doc["apiKey"] = _apiKey;
146+
doc["secret"] = _secret;
147+
148+
String message;
149+
serializeJson(doc, message);
150+
webSocket.sendTXT(message);
151+
}
152+
153+
// Handle incoming WebSocket messages
154+
void SciFyIoT::handleWebSocketMessage(const char* message) {
155+
DynamicJsonDocument doc(512);
156+
DeserializationError error = deserializeJson(doc, message);
157+
158+
if (error) return;
159+
160+
String type = doc["type"];
161+
162+
if (type == "auth_success") {
163+
authenticated = true;
164+
digitalWrite(LED_BUILTIN, LOW);
165+
lastHeartbeat = millis();
166+
if (_statusCallback) _statusCallback(true, true);
167+
}
168+
else if (type == "auth_error") {
169+
authenticated = false;
170+
digitalWrite(LED_BUILTIN, HIGH);
171+
if (_statusCallback) _statusCallback(true, false);
172+
}
173+
else if (type == "command" && authenticated) {
174+
String commandId = doc["id"];
175+
String payload = doc["payload"];
176+
177+
bool handled = executeDefaultCommand(payload);
178+
179+
if (!handled && _commandCallback) {
180+
_commandCallback(payload, commandId);
181+
} else if (handled) {
182+
sendAck(commandId, "executed");
183+
} else {
184+
sendAck(commandId, "failed");
185+
}
186+
}
187+
}
188+
189+
// Execute default commands
190+
bool SciFyIoT::executeDefaultCommand(const String& command) {
191+
if (command == "LED_ON") {
192+
digitalWrite(LED_BUILTIN, LOW);
193+
return true;
194+
}
195+
else if (command == "LED_OFF") {
196+
digitalWrite(LED_BUILTIN, HIGH);
197+
return true;
198+
}
199+
else if (command == "STATUS") {
200+
sendSensorData();
201+
return true;
202+
}
203+
else if (command == "RESTART") {
204+
ESP.restart();
205+
return true;
206+
}
207+
208+
return false;
209+
}
210+
211+
// Send acknowledgement
212+
void SciFyIoT::sendAck(const String& commandId, const String& status) {
213+
DynamicJsonDocument doc(256);
214+
doc["type"] = "ack";
215+
doc["commandId"] = commandId;
216+
doc["status"] = status;
217+
doc["timestamp"] = millis();
218+
219+
String message;
220+
serializeJson(doc, message);
221+
webSocket.sendTXT(message);
222+
}
223+
224+
// Send heartbeat
225+
void SciFyIoT::sendHeartbeat() {
226+
if (!authenticated) return;
227+
228+
DynamicJsonDocument doc(128);
229+
doc["type"] = "heartbeat";
230+
doc["timestamp"] = millis();
231+
232+
String message;
233+
serializeJson(doc, message);
234+
webSocket.sendTXT(message);
235+
}
236+
237+
// Send sensor data
238+
void SciFyIoT::sendSensorData(float temperature, float humidity) {
239+
DynamicJsonDocument doc(256);
240+
doc["type"] = "sensor_data";
241+
doc["payload"]["temperature"] = temperature;
242+
doc["payload"]["humidity"] = humidity;
243+
doc["payload"]["uptime"] = millis();
244+
doc["payload"]["free_heap"] = ESP.getFreeHeap();
245+
doc["payload"]["wifi_rssi"] = WiFi.RSSI();
246+
doc["timestamp"] = millis();
247+
248+
String message;
249+
serializeJson(doc, message);
250+
webSocket.sendTXT(message);
251+
}
252+
253+
// Send custom data
254+
void SciFyIoT::sendCustomData(const String& dataType, JsonObject& data) {
255+
DynamicJsonDocument doc(512);
256+
doc["type"] = dataType;
257+
doc["payload"] = data;
258+
doc["timestamp"] = millis();
259+
260+
String message;
261+
serializeJson(doc, message);
262+
webSocket.sendTXT(message);
263+
}
264+
265+
// Send response
266+
void SciFyIoT::sendResponse(const String& commandId, const String& status, const String& data) {
267+
sendAck(commandId, status);
268+
}
269+
270+
// Check connection health
271+
void SciFyIoT::checkConnection() {
272+
if (millis() - lastActivity > connectionTimeout) {
273+
webSocket.disconnect();
274+
authenticated = false;
275+
lastActivity = millis();
276+
}
277+
}
278+
279+
// Set command callback
280+
void SciFyIoT::onCommandReceived(CommandCallback callback) {
281+
_commandCallback = callback;
282+
}
283+
284+
// Set status callback
285+
void SciFyIoT::onStatusChanged(StatusCallback callback) {
286+
_statusCallback = callback;
287+
}
288+
289+
// Restart device
290+
void SciFyIoT::restart() {
291+
ESP.restart();
292+
}
293+
294+
// Enable/disable built-in LED
295+
void SciFyIoT::enableBuiltinLED(bool enable) {
296+
if (enable) {
297+
pinMode(LED_BUILTIN, OUTPUT);
298+
}
299+
}

SciFyIoT.h

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
#ifndef SCIFYIOT_H
2+
#define SCIFYIOT_H
3+
4+
#if defined(ESP8266)
5+
#include <ESP8266WiFi.h>
6+
#elif defined(ESP32)
7+
#include <WiFi.h>
8+
#else
9+
#error "Unsupported board. Use ESP8266 or ESP32."
10+
#endif
11+
12+
#include <WebSocketsClient.h>
13+
#include <ArduinoJson.h>
14+
15+
// Callback function types
16+
typedef void (*CommandCallback)(const String& command, const String& commandId);
17+
typedef void (*StatusCallback)(bool connected, bool authenticated);
18+
19+
class SciFyIoT {
20+
private:
21+
WebSocketsClient webSocket;
22+
23+
// Configuration
24+
String _ssid;
25+
String _password;
26+
String _apiKey;
27+
String _secret;
28+
String _serverUrl;
29+
int _serverPort;
30+
String _serverPath;
31+
32+
// State variables
33+
bool authenticated;
34+
unsigned long lastHeartbeat;
35+
unsigned long lastActivity;
36+
static const unsigned long heartbeatInterval = 25000;
37+
static const unsigned long connectionTimeout = 60000;
38+
39+
// Callbacks
40+
CommandCallback _commandCallback;
41+
StatusCallback _statusCallback;
42+
43+
// Private methods
44+
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length);
45+
void authenticateDevice();
46+
void handleWebSocketMessage(const char* message);
47+
bool executeDefaultCommand(const String& command);
48+
void sendAck(const String& commandId, const String& status);
49+
void sendHeartbeat();
50+
void checkConnection();
51+
void connectWiFi();
52+
53+
// Static callback wrapper for WebSocket events
54+
static SciFyIoT* instance;
55+
static void webSocketEventWrapper(WStype_t type, uint8_t * payload, size_t length);
56+
57+
public:
58+
// Constructor
59+
SciFyIoT();
60+
61+
// Initialization
62+
void begin(const char* ssid, const char* password, const char* apiKey, const char* secret);
63+
void begin(const char* ssid, const char* password, const char* apiKey, const char* secret,
64+
const char* serverUrl, int serverPort = 443, const char* serverPath = "/ws");
65+
66+
// Main loop - call this in Arduino loop()
67+
void loop();
68+
69+
// Status methods
70+
bool isConnected();
71+
bool isAuthenticated();
72+
bool isWiFiConnected();
73+
74+
// Communication methods
75+
void sendSensorData(float temperature = 25.5, float humidity = 60.0);
76+
void sendCustomData(const String& dataType, JsonObject& data);
77+
void sendResponse(const String& commandId, const String& status, const String& data = "");
78+
79+
// Callback setters
80+
void onCommandReceived(CommandCallback callback);
81+
void onStatusChanged(StatusCallback callback);
82+
83+
// Utility methods
84+
void restart();
85+
void enableBuiltinLED(bool enable = true);
86+
};
87+
88+
#endif

0 commit comments

Comments
 (0)