Skip to main content
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

1

Create Google Cloud Project

  1. Go to Google Cloud Console
  2. Create a new project or select existing
  3. Enable Google Sheets API
2

Create Service Account

  1. Navigate to IAM & Admin > Service Accounts
  2. Click β€œCreate Service Account”
  3. Give it a name (e.g., β€œESP32 Logger”)
  4. Grant role β€œEditor” or β€œOwner”
  5. Create and download JSON key file
3

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)
4

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

1

Create Bot

  1. Open Telegram and search for β€œ@BotFather”
  2. Send /newbot command
  3. Follow prompts to name your bot
  4. Save the bot token (e.g., 123456789:ABCdefGHIjklMNOpqrsTUVwxyz)
2

Get Chat ID

  1. Send a message to your bot
  2. Visit: https://api.telegram.org/bot<YourBotToken>/getUpdates
  3. Find "chat":{"id":123456789} in the JSON response
  4. 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

1

Get API Key

  1. Add CallMeBot to your WhatsApp contacts: +34 644 44 85 45
  2. Send message: I allow callmebot to send me messages
  3. You’ll receive your API key
2

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

Multi-Platform Alerts

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
ready
bool()
Check if authenticated and ready
process
void()
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

begin
void(onBegin)
Initialize bot with optional callback
setChatId
void(chatId)
Set authorized chat ID
sendMessages
void(message)
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
sendMessages
bool(message, callback)
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

Build docs developers (and LLMs) love