Skip to content

Instantly share code, notes, and snippets.

@Tech500
Last active November 7, 2025 17:20
Show Gist options
  • Select an option

  • Save Tech500/e025e6d035de917bf006118962441ce1 to your computer and use it in GitHub Desktop.

Select an option

Save Tech500/e025e6d035de917bf006118962441ce1 to your computer and use it in GitHub Desktop.
WOR Ack function --Claude

Here's an ESP32-S3 optimized version with these features: --Claude

Key ESP32-S3 optimizations:

  1. Arduino framework - Uses Arduino.h instead of ESP-IDF (easier to use)
  2. mbedTLS for SHA256 - Built into ESP32, no external dependencies
  3. millis() for timestamps - Uses ESP32's millisecond timer
  4. String class - ESP32-native string handling
  5. Low memory footprint - Optimized for embedded use

Integration examples included for:

  • LoRa - For long-range radio communication
  • WiFi/HTTP - For internet connectivity
  • BLE - For Bluetooth Low Energy

To use:

  1. Replace actualSendFunction() with your specific radio protocol
  2. Uncomment the example that matches your hardware (LoRa, WiFi, BLE)
  3. Configure your device secret key
  4. Upload to your ESP32-S3

The code uses ESP32's built-in mbedtls library for cryptographic operations, so no external dependencies needed!

#include <Arduino.h>
#include "mbedtls/md.h"
#include <string>
enum class RetryStrategy {
EXPONENTIAL,
LINEAR,
FIXED
};
struct WoREvent {
String device_id;
String event_type;
unsigned long timestamp;
String action;
String status;
unsigned long ack_timestamp;
String ack_signature;
int retry_count;
WoREvent(const String& dev_id, const String& evt_type, const String& act)
: device_id(dev_id), event_type(evt_type), action(act),
status("pending"), ack_timestamp(0), retry_count(0) {
timestamp = millis();
}
};
struct AckPayload {
String device_id;
String event_type;
unsigned long original_timestamp;
unsigned long ack_timestamp;
String status;
String action_taken;
String signature;
int retry_count;
String notes;
String toJSON() const {
String json = "{";
json += "\"device_id\":\"" + device_id + "\",";
json += "\"event_type\":\"" + event_type + "\",";
json += "\"original_timestamp\":" + String(original_timestamp) + ",";
json += "\"ack_timestamp\":" + String(ack_timestamp) + ",";
json += "\"status\":\"" + status + "\",";
json += "\"action_taken\":\"" + action_taken + "\",";
json += "\"signature\":\"" + signature + "\",";
json += "\"retry_count\":" + String(retry_count) + ",";
json += "\"notes\":\"" + notes + "\"";
json += "}";
return json;
}
};
class WoRAcknowledgment {
private:
String sha256(const String& input) {
byte hash[32];
mbedtls_md_context_t ctx;
mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256;
mbedtls_md_init(&ctx);
mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 0);
mbedtls_md_starts(&ctx);
mbedtls_md_update(&ctx, (const unsigned char*)input.c_str(), input.length());
mbedtls_md_finish(&ctx, hash);
mbedtls_md_free(&ctx);
String hash_str = "";
for(int i = 0; i < 32; i++) {
char hex[3];
sprintf(hex, "%02x", hash[i]);
hash_str += hex;
}
return hash_str;
}
unsigned long calculateDelay(int attempt, unsigned long base_delay,
unsigned long max_delay, RetryStrategy strategy) {
unsigned long delay;
switch(strategy) {
case RetryStrategy::EXPONENTIAL:
delay = base_delay * (1 << attempt); // bit shift for power of 2
break;
case RetryStrategy::LINEAR:
delay = base_delay * (attempt + 1);
break;
case RetryStrategy::FIXED:
default:
delay = base_delay;
break;
}
return min(delay, max_delay);
}
public:
AckPayload acknowledgeWoREvent(WoREvent& event, const String& device_secret,
bool success = true, const String& notes = "") {
// Update event status
event.status = success ? "completed" : "failed";
event.ack_timestamp = millis();
// Generate acknowledgment signature
String ack_data = event.device_id + ":" + event.event_type + ":" +
String(event.ack_timestamp) + ":" + event.status;
String sig_input = ack_data + ":" + device_secret;
event.ack_signature = sha256(sig_input);
// Build acknowledgment payload
AckPayload payload;
payload.device_id = event.device_id;
payload.event_type = event.event_type;
payload.original_timestamp = event.timestamp;
payload.ack_timestamp = event.ack_timestamp;
payload.status = event.status;
payload.action_taken = event.action;
payload.signature = event.ack_signature;
payload.retry_count = event.retry_count;
payload.notes = notes;
return payload;
}
bool sendAcknowledgmentWithRetry(
WoREvent& event,
const String& device_secret,
bool (*send_function)(const AckPayload&),
bool success = true,
const String& notes = "",
int max_retries = 3,
unsigned long base_delay = 1000, // milliseconds
unsigned long max_delay = 30000,
RetryStrategy strategy = RetryStrategy::EXPONENTIAL
) {
// Generate initial acknowledgment payload
AckPayload ack_payload = acknowledgeWoREvent(event, device_secret, success, notes);
// Attempt to send with retries
for(int attempt = 0; attempt <= max_retries; attempt++) {
Serial.printf("Attempt %d/%d: Sending acknowledgment...\n",
attempt + 1, max_retries + 1);
bool send_result = false;
// Try-catch equivalent for ESP32
if(send_function != nullptr) {
send_result = send_function(ack_payload);
}
if(send_result) {
Serial.printf("✓ Acknowledgment sent successfully on attempt %d\n",
attempt + 1);
return true;
}
// If send failed and we have retries left
if(attempt < max_retries) {
event.retry_count++;
unsigned long delay = calculateDelay(attempt, base_delay, max_delay, strategy);
Serial.printf("✗ Send failed. Retrying in %lu ms...\n", delay);
delay(delay);
// Regenerate payload with updated retry count
ack_payload = acknowledgeWoREvent(event, device_secret, success, notes);
}
}
Serial.printf("✗ Failed to send acknowledgment after %d attempts\n",
max_retries + 1);
return false;
}
};
// Global instance
WoRAcknowledgment ack_handler;
// Mock send function for testing (simulates LoRa/WiFi/BLE transmission)
bool mockSendFunction(const AckPayload& payload) {
static int call_count = 0;
call_count++;
Serial.println(" → Attempting to send payload:");
Serial.println(" " + payload.toJSON());
// Simulate 40% success rate (typically succeeds on 2nd or 3rd attempt)
if(call_count >= 2 && (random(100) > 60)) {
Serial.println(" → Mock send successful");
return true;
} else {
Serial.println(" → Mock send failed (simulated network error)");
return false;
}
}
// Replace this with your actual send function (LoRa, WiFi, BLE, etc.)
bool actualSendFunction(const AckPayload& payload) {
// Example for LoRa:
// LoRa.beginPacket();
// LoRa.print(payload.toJSON());
// return LoRa.endPacket() == 1;
// Example for WiFi/HTTP:
// HTTPClient http;
// http.begin("http://your-server.com/ack");
// http.addHeader("Content-Type", "application/json");
// int httpCode = http.POST(payload.toJSON());
// http.end();
// return (httpCode == 200);
// Example for BLE:
// pCharacteristic->setValue(payload.toJSON().c_str());
// pCharacteristic->notify();
// return true;
return mockSendFunction(payload);
}
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("\n=== ESP32-S3 Wake-on-Radio Acknowledgment Test ===\n");
// Create a WoR event
WoREvent wor_event("VALVE_001", "valve_control", "close_valve");
Serial.printf("Received WoR event: %s for device %s\n\n",
wor_event.action.c_str(), wor_event.device_id.c_str());
// Simulate performing the action (e.g., closing valve)
// digitalWrite(VALVE_PIN, HIGH);
// delay(500);
// ... actual hardware control code here ...
String device_secret = "your_device_secret_key";
// Send acknowledgment with retry logic
bool result = ack_handler.sendAcknowledgmentWithRetry(
wor_event,
device_secret,
actualSendFunction,
true, // success
"Valve successfully closed at 50% position",
3, // max_retries
1000, // base_delay (1 second)
30000, // max_delay (30 seconds)
RetryStrategy::EXPONENTIAL
);
Serial.println("\n==================================================");
Serial.printf("Final result: %s\n", result ? "SUCCESS" : "FAILED");
Serial.printf("Total retry attempts: %d\n", wor_event.retry_count);
Serial.println("==================================================\n");
}
void loop() {
// Your main loop code here
delay(10000);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment