Kinematrix provides ready-to-use integrations with popular cloud services for data logging, notifications, and remote control capabilities.
Available Integrations
Google Sheets
Log sensor data directly to spreadsheets with service account authentication
Telegram Bot
Send notifications and receive commands via Telegram
WhatsApp
Send messages through WhatsApp Business API
Google Sheets Integration
Log data directly to Google Sheets for easy visualization and analysis.
Features
- Direct API access to Google Sheets
- Service account authentication
- Create, read, update spreadsheets
- Batch operations for efficiency
- Multiple WiFi network support
- mDNS support
Dependencies
Add to platformio.ini:
lib_deps =
mobizt/ESP-Google-Sheet-Client@^1.4.4
bblanchon/ArduinoJson@^6.21.3
Enable Module
#define ENABLE_MODULE_GOOGLE_SHEETS
#include "Kinematrix.h"
Setup Google Service Account
Create Google Cloud Project
Create Service Account
- Navigate to IAM & Admin > Service Accounts
- Click βCreate Service Accountβ
- Give it a name (e.g., βESP32 Loggerβ)
- Grant role βEditorβ or βOwnerβ
- Create and download JSON key file
Extract Credentials
From the downloaded JSON file, extract:
client_email: Service account email
project_id: Your project ID
private_key: Private key (including BEGIN/END markers)
Share Spreadsheet
Share your Google Sheet with the service account email address (viewer or editor access)
Basic Usage
#include <WiFi.h>
#define ENABLE_MODULE_GOOGLE_SHEETS
#include "Kinematrix.h"
GoogleSheetClient sheets;
const char* CLIENT_EMAIL = "[email protected]";
const char* PROJECT_ID = "your-project-id";
const char* PRIVATE_KEY =
"-----BEGIN PRIVATE KEY-----\n"
"MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC...\n"
"-----END PRIVATE KEY-----\n";
void setup() {
Serial.begin(115200);
// Connect to WiFi
WiFi.begin("SSID", "password");
while (WiFi.status() != WL_CONNECTED) {
delay(100);
}
Serial.println("WiFi connected");
// Initialize Google Sheets client
sheets.begin(CLIENT_EMAIL, PROJECT_ID, PRIVATE_KEY);
// Wait for authentication
while (!sheets.ready()) {
sheets.process();
delay(100);
}
Serial.println("Google Sheets ready!");
}
void loop() {
sheets.process(); // Process authentication tokens
}
Create Spreadsheet
String spreadsheetId = sheets.createSpreadsheet(
"Sensor Data Log", // Spreadsheet title
"Sheet1", // First sheet name
100, // Number of rows
10, // Number of columns
"[email protected]" // Share with this email
);
if (spreadsheetId.length() > 0) {
Serial.println("Spreadsheet ID: " + spreadsheetId);
Serial.println("URL: https://docs.google.com/spreadsheets/d/" + spreadsheetId);
} else {
Serial.println("Error: " + sheets.errorReason());
}
Write Data
#include <ArduinoJson.h>
void logSensorData(String spreadsheetId, float temperature, float humidity) {
// Create value range JSON
FirebaseJson valueRange;
FirebaseJsonArray values;
FirebaseJsonArray row;
// Add timestamp, temperature, humidity
row.add(String(millis() / 1000));
row.add(String(temperature, 2));
row.add(String(humidity, 2));
values.add(row);
valueRange.add("values", values);
// Append to sheet
bool success = sheets.appendValues(
spreadsheetId.c_str(),
"Sheet1!A:C", // Range
&valueRange
);
if (success) {
Serial.println("Data logged successfully");
} else {
Serial.println("Error: " + sheets.errorReason());
}
}
Read Data
String data = sheets.getValues(
spreadsheetId.c_str(),
"Sheet1!A1:C10" // Read range A1 to C10
);
if (data.length() > 0) {
Serial.println("Data from sheet:");
Serial.println(data);
} else {
Serial.println("Error: " + sheets.errorReason());
}
Update Data
FirebaseJson valueRange;
FirebaseJsonArray values;
FirebaseJsonArray row;
row.add("Updated Value");
values.add(row);
valueRange.add("values", values);
sheets.updateValues(
spreadsheetId.c_str(),
"Sheet1!A1", // Cell to update
&valueRange
);
Batch Operations
FirebaseJsonArray valueRangeArray;
// First range
FirebaseJson range1;
FirebaseJsonArray values1;
FirebaseJsonArray row1;
row1.add("Value 1");
values1.add(row1);
range1.add("range", "Sheet1!A1");
range1.add("values", values1);
valueRangeArray.add(range1);
// Second range
FirebaseJson range2;
FirebaseJsonArray values2;
FirebaseJsonArray row2;
row2.add("Value 2");
values2.add(row2);
range2.add("range", "Sheet1!B1");
range2.add("values", values2);
valueRangeArray.add(range2);
// Batch update
sheets.batchUpdateValues(
spreadsheetId.c_str(),
&valueRangeArray
);
Practical Example: Temperature Logger
#include <WiFi.h>
#define ENABLE_MODULE_GOOGLE_SHEETS
#include "Kinematrix.h"
GoogleSheetClient sheets;
String spreadsheetId = "YOUR_SPREADSHEET_ID";
void setup() {
Serial.begin(115200);
WiFi.begin("SSID", "password");
while (WiFi.status() != WL_CONNECTED) delay(100);
sheets.begin(CLIENT_EMAIL, PROJECT_ID, PRIVATE_KEY);
while (!sheets.ready()) {
sheets.process();
delay(100);
}
// Create header row
FirebaseJson header;
FirebaseJsonArray values;
FirebaseJsonArray row;
row.add("Timestamp");
row.add("Temperature");
row.add("Humidity");
values.add(row);
header.add("values", values);
sheets.updateValues(spreadsheetId.c_str(), "Sheet1!A1:C1", &header);
}
void loop() {
sheets.process();
static unsigned long lastLog = 0;
if (millis() - lastLog >= 300000) { // Every 5 minutes
lastLog = millis();
float temp = readTemperature();
float humidity = readHumidity();
// Log to sheet
FirebaseJson valueRange;
FirebaseJsonArray values;
FirebaseJsonArray row;
row.add(getTimestamp());
row.add(String(temp, 2));
row.add(String(humidity, 2));
values.add(row);
valueRange.add("values", values);
sheets.appendValues(spreadsheetId.c_str(), "Sheet1!A:C", &valueRange);
Serial.println("Data logged: " + String(temp) + "C, " + String(humidity) + "%");
}
}
Telegram Bot Integration
Receive notifications and send commands to your ESP32 via Telegram.
Features
- Send messages to users
- Receive commands from authorized users
- Callback-based message handling
- Automatic polling for new messages
- User authorization
Dependencies
lib_deps =
witnessmenow/UniversalTelegramBot@^1.3.0
bblanchon/ArduinoJson@^6.21.3
Enable Module
#define ENABLE_MODULE_TELEGRAM_BOT
#include "Kinematrix.h"
Setup Telegram Bot
Create Bot
- Open Telegram and search for β@BotFatherβ
- Send
/newbot command
- Follow prompts to name your bot
- Save the bot token (e.g.,
123456789:ABCdefGHIjklMNOpqrsTUVwxyz)
Get Chat ID
- Send a message to your bot
- Visit:
https://api.telegram.org/bot<YourBotToken>/getUpdates
- Find
"chat":{"id":123456789} in the JSON response
- Save your chat ID
Basic Usage
#include <WiFi.h>
#include <WiFiClientSecure.h>
#define ENABLE_MODULE_TELEGRAM_BOT
#include "Kinematrix.h"
WiFiClientSecure client;
TelegramBot bot("YOUR_BOT_TOKEN", client);
String chatId = "YOUR_CHAT_ID";
void setup() {
Serial.begin(115200);
WiFi.begin("SSID", "password");
while (WiFi.status() != WL_CONNECTED) delay(100);
// Required for Telegram SSL
client.setInsecure();
bot.setChatId(chatId);
bot.begin();
Serial.println("Bot ready!");
}
void loop() {
// Check for messages every 1 second
bot.onReceiveMessages(1000, handleMessage);
}
void handleMessage(const String& fromName, const String& text) {
Serial.println("From: " + fromName);
Serial.println("Message: " + text);
// Process commands
if (text == "/start") {
bot.sendMessages("Hello! I'm your ESP32 bot.");
}
else if (text == "/status") {
String status = "Uptime: " + String(millis() / 1000) + "s";
bot.sendMessages(status);
}
else if (text == "/temp") {
float temp = readTemperature();
bot.sendMessages("Temperature: " + String(temp, 1) + "C");
}
}
Send Notifications
void sendAlert(String message) {
bot.sendMessages("π¨ ALERT: " + message);
}
void loop() {
float temp = readTemperature();
if (temp > 30.0) {
sendAlert("Temperature too high: " + String(temp, 1) + "C");
delay(60000); // Wait 1 minute before next alert
}
}
Control Devices
int ledPin = 2;
bool ledState = false;
void handleMessage(const String& fromName, const String& text) {
if (text == "/led_on") {
ledState = true;
digitalWrite(ledPin, HIGH);
bot.sendMessages("LED turned ON");
}
else if (text == "/led_off") {
ledState = false;
digitalWrite(ledPin, LOW);
bot.sendMessages("LED turned OFF");
}
else if (text == "/led_status") {
String status = ledState ? "ON" : "OFF";
bot.sendMessages("LED is " + status);
}
}
Error Handling
void onUnauthorized() {
Serial.println("Unauthorized user attempted access");
// Bot automatically sends "Unauthorized user" message
}
void setup() {
// ... WiFi setup ...
bot.begin(onUnauthorized);
}
void loop() {
bot.onReceiveMessages(1000, handleMessage, onUnauthorized);
}
Practical Example: Smart Home Control
#include <WiFi.h>
#include <WiFiClientSecure.h>
#define ENABLE_MODULE_TELEGRAM_BOT
#include "Kinematrix.h"
WiFiClientSecure client;
TelegramBot bot("BOT_TOKEN", client);
String chatId = "CHAT_ID";
int relayPin = 5;
bool relayState = false;
void setup() {
Serial.begin(115200);
pinMode(relayPin, OUTPUT);
WiFi.begin("SSID", "password");
while (WiFi.status() != WL_CONNECTED) delay(100);
client.setInsecure();
bot.setChatId(chatId);
bot.begin();
bot.sendMessages("π Smart Home System Online");
}
void loop() {
bot.onReceiveMessages(1000, handleCommand);
// Monitor sensors and send alerts
static unsigned long lastCheck = 0;
if (millis() - lastCheck >= 60000) {
lastCheck = millis();
checkSensors();
}
}
void handleCommand(const String& from, const String& cmd) {
Serial.println(from + ": " + cmd);
if (cmd == "/start") {
bot.sendMessages(
"Welcome to Smart Home Control\n"
"/relay_on - Turn relay ON\n"
"/relay_off - Turn relay OFF\n"
"/status - System status\n"
"/temp - Temperature reading"
);
}
else if (cmd == "/relay_on") {
relayState = true;
digitalWrite(relayPin, HIGH);
bot.sendMessages("β
Relay turned ON");
}
else if (cmd == "/relay_off") {
relayState = false;
digitalWrite(relayPin, LOW);
bot.sendMessages("β Relay turned OFF");
}
else if (cmd == "/status") {
String msg = "π System Status\n";
msg += "Relay: " + String(relayState ? "ON" : "OFF") + "\n";
msg += "Uptime: " + String(millis() / 60000) + " minutes\n";
msg += "WiFi RSSI: " + String(WiFi.RSSI()) + " dBm";
bot.sendMessages(msg);
}
else if (cmd == "/temp") {
float temp = readTemperature();
bot.sendMessages("π‘ Temperature: " + String(temp, 1) + "Β°C");
}
else {
bot.sendMessages("Unknown command. Send /start for help.");
}
}
void checkSensors() {
float temp = readTemperature();
if (temp > 35.0) {
bot.sendMessages("β οΈ High temperature alert: " + String(temp, 1) + "Β°C");
}
}
WhatsApp Integration
Send WhatsApp messages using CallMeBot API.
Features
- Send text messages
- No official WhatsApp Business API required
- Simple HTTP-based interface
- Result callback support
Enable Module
#define ENABLE_MODULE_WHATSAPP_BOT
#include "Kinematrix.h"
Setup CallMeBot
Get API Key
- Add CallMeBot to your WhatsApp contacts: +34 644 44 85 45
- Send message:
I allow callmebot to send me messages
- Youβll receive your API key
Get Phone Number
Use your WhatsApp phone number in international format (without + or spaces)Example: For +1 234 567 8900, use 12345678900
Basic Usage
#include <WiFi.h>
#define ENABLE_MODULE_WHATSAPP_BOT
#include "Kinematrix.h"
WhatsappBot whatsapp;
String phoneNumber = "12345678900"; // Your phone number
String apiKey = "YOUR_API_KEY";
void setup() {
Serial.begin(115200);
WiFi.begin("SSID", "password");
while (WiFi.status() != WL_CONNECTED) delay(100);
whatsapp.init(phoneNumber, apiKey);
whatsapp.sendMessages("ESP32 is online!");
}
Send Messages
whatsapp.sendMessages("Hello from ESP32!");
// With callback
whatsapp.sendMessages(
"Sensor alert: Temperature high",
onMessageSent
);
void onMessageSent(const String& response, const String& error) {
if (error.length() == 0) {
Serial.println("Message sent successfully");
Serial.println("Response: " + response);
} else {
Serial.println("Error: " + error);
}
}
Send Alerts
void loop() {
float temp = readTemperature();
static bool alertSent = false;
if (temp > 30.0 && !alertSent) {
String message = "Temperature Alert: " + String(temp, 1) + "C";
whatsapp.sendMessages(message);
alertSent = true;
}
else if (temp <= 30.0) {
alertSent = false; // Reset alert
}
}
Practical Example: Security System
#include <WiFi.h>
#define ENABLE_MODULE_WHATSAPP_BOT
#include "Kinematrix.h"
WhatsappBot whatsapp("12345678900", "API_KEY");
int pirPin = 4;
bool motionDetected = false;
void setup() {
Serial.begin(115200);
pinMode(pirPin, INPUT);
WiFi.begin("SSID", "password");
while (WiFi.status() != WL_CONNECTED) delay(100);
whatsapp.sendMessages("π Security system activated");
}
void loop() {
if (digitalRead(pirPin) == HIGH && !motionDetected) {
motionDetected = true;
String alert = "π¨ MOTION DETECTED\n";
alert += "Time: " + getTimestamp() + "\n";
alert += "Location: Front Door";
whatsapp.sendMessages(alert, onAlertSent);
delay(60000); // 1 minute cooldown
motionDetected = false;
}
}
void onAlertSent(const String& res, const String& err) {
if (err.length() > 0) {
Serial.println("Failed to send alert: " + err);
}
}
CallMeBot Limitations:
- Rate limited to prevent spam
- Message length limits apply
- Free service may have availability issues
- Consider WhatsApp Business API for production
Best Practices
Rate Limiting: Donβt send too many messages too quickly. Add delays between messages.
Error Handling: Always implement callbacks to detect failed API calls and retry if necessary.
Security: Never commit API keys or tokens to version control. Use environment variables.
Combining Services
void sendAlert(String message) {
// Log to Google Sheets
logToSheets(message);
// Send Telegram notification
bot.sendMessages("π¨ " + message);
// Send WhatsApp for critical alerts
if (message.indexOf("CRITICAL") >= 0) {
whatsapp.sendMessages(message);
}
}
API Reference
Google Sheets
begin
bool(clientEmail, projectId, privateKey)
Initialize with service account credentials
Check if authenticated and ready
Process authentication tokens (call in loop)
createSpreadsheet
String(title, sheetName, rows, cols, email)
Create new spreadsheet and return ID
updateValues
bool(spreadsheetId, range, valueRange)
Update cell values in range
appendValues
bool(spreadsheetId, range, valueRange)
Append rows to sheet
getValues
String(spreadsheetId, range)
Read values from range
Telegram Bot
Initialize bot with optional callback
Send message to authorized chat
onReceiveMessages
void(interval, onReceive, onError)
Poll for messages every interval (ms) with callbacks
WhatsApp Bot
init
bool(phoneNumber, apiKey)
Initialize with CallMeBot credentials
Send message with optional result callback
Next Steps
MQTT Communication
Combine with MQTT for bidirectional communication
Firebase Integration
Use Firebase for real-time data sync