Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/node config update #4

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
4 changes: 2 additions & 2 deletions examples/arduino/host/Host.ino
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ EspNowHost::OnLog _on_log = [](const std::string message, const esp_log_level_t

EspNowCrypt _esp_now_crypt(esp_now_encryption_key, esp_now_encryption_secret);
EspNowHost _esp_now_host(_esp_now_crypt, EspNowHost::WiFiInterface::STA, _on_new_message, _on_application_message,
_firmware_update_available, _on_log);
_firmware_update_available, NULL, _on_log);

void setup() {
Serial.begin(115200);
Expand Down Expand Up @@ -129,4 +129,4 @@ void loop() {
digitalWrite(LED_PIN, LOW);
_turn_of_led_at_ms = -1;
}
}
}
159 changes: 159 additions & 0 deletions examples/arduino/host_with_configuration/Host.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
#include "shared/esp-now-structs.h"
#include <Arduino.h>
#include <EspNowCrypt.h>
#include <EspNowHost.h>
#include <WiFi.h>
#include <esp_wifi.h>

// These structs are the application messages shared across the host and node device.
#pragma pack(1)
struct MyApplicationMessage {
uint8_t id = 0x01;
bool open;
};
struct MySecondApplicationMessage {
uint8_t id = 0x02;
double temperature;
};
struct MyConfigMessageV1 {
uint32_t sleep_seconds;
uint8_t foo;
};
#pragma pack(0)

// Change this to your LED pin
#define LED_PIN GPIO_NUM_15

const char wifi_ssid[] = "my-wifi-ssid";
const char wifi_password[] = "my-wifi-password";
// Encyption key used for our own packet encryption (GCM).
// We are not using the esp-now encryption due to the peer limitation.
// The key should be the same for both the host and the node.
const char esp_now_encryption_key[] = "0123456789ABCDEF"; // Must be exact 16 bytes long. \0 does not count.

// Used to validate the integrity of the messages.
// The secret should be the same for both the host and the node.
const char esp_now_encryption_secret[] = "01234567"; // Must be exact 8 bytes long. \0 does not count.

unsigned long _turn_of_led_at_ms = 0;

EspNowHost::OnNewMessage _on_new_message = []() {
// Callback on any new message. Turn on led to indicate this.
digitalWrite(LED_PIN, HIGH);
_turn_of_led_at_ms = millis() + 1000;
};

EspNowHost::OnApplicationMessage _on_application_message = [](EspNowHost::MessageMetadata metadata,
const uint8_t *message) {
// Callback for new application messages.
auto id = message[0];
Serial.println("Got message from 0x" + String(metadata.mac_address) + " with ID " + id);
switch (id) {
case 0x01: {
MyApplicationMessage *msg = (MyApplicationMessage *)message;
Serial.println("MyApplicationMessage::open: " + String(msg->open));
break;
}
case 0x02: {
MySecondApplicationMessage *msg = (MySecondApplicationMessage *)message;
Serial.println("MyApplicationMessage::temperature: " + String(msg->temperature));
break;
}
default: {
Serial.println("Unknown message id: " + String(id));
}
}
};

EspNowHost::FirmwareUpdateAvailable _firmware_update_available = [](uint64_t mac_address, uint32_t firmware_version) {
// Callback where we can indicate if there is a new firmware available.
return std::nullopt;
};

EspNowHost::ConfigurationUpdateAvailable _config_update_available = [](uint64_t mac_address,
uint16_t configuration_revision) {
Serial.println(("_config_update_available start ver=" + std::to_string(configuration_revision)).c_str());
if (configuration_revision != 1) {
EspNowConfigEnvelope env;
env.version = 1;
MyConfigMessageV1 cfg;
cfg.sleep_seconds = 30;
cfg.foo = 111;
env.length = sizeof(MyConfigMessageV1);
memcpy(&env.payload, &cfg, env.length);
return (std::optional<EspNowConfigEnvelope>)env;
}

return (std::optional<EspNowConfigEnvelope>)std::nullopt;
};

EspNowHost::OnLog _on_log = [](const std::string message, const esp_log_level_t log_level) {
// Callback for logging. Can be omitted.
if (log_level == ESP_LOG_NONE) {
return; // Weird flex, but ok
}

std::string level;
switch (log_level) {
case ESP_LOG_NONE:
level = "none";
break;
case ESP_LOG_ERROR:
level = "error";
break;
case ESP_LOG_WARN:
level = "warning";
break;
case ESP_LOG_INFO:
level = "info";
break;
case ESP_LOG_DEBUG:
level = "debug";
break;
case ESP_LOG_VERBOSE:
level = "verbose";
break;
default:
level = "unknown";
break;
}

Serial.println(("EspNowHost (" + level + "): " + message).c_str());
};

EspNowCrypt _esp_now_crypt(esp_now_encryption_key, esp_now_encryption_secret);
EspNowHost _esp_now_host(_esp_now_crypt, EspNowHost::WiFiInterface::STA, _on_new_message, _on_application_message,
_firmware_update_available, _config_update_available, _on_log);

void setup() {
Serial.begin(115200);

// Setup WiFI
WiFi.mode(WIFI_STA);
WiFi.begin(wifi_ssid, wifi_password);
while (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.println("Connection Failed! Rebooting...");
delay(5000);
ESP.restart();
}
Serial.println("have wifi");
Serial.print("IP number: ");
Serial.println(WiFi.localIP());
Serial.print("Channel: ");
Serial.println(WiFi.channel());

pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, HIGH);
_turn_of_led_at_ms = millis() + 1000;

esp_wifi_set_ps(WIFI_PS_NONE); // No sleep on WiFi to be able to receive ESP-NOW packages without being in AP mode.

_esp_now_host.setup();
}

void loop() {
if (_turn_of_led_at_ms > 0 && millis() > _turn_of_led_at_ms) {
digitalWrite(LED_PIN, LOW);
_turn_of_led_at_ms = -1;
}
}
37 changes: 32 additions & 5 deletions examples/arduino/node/Node.ino
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
#include <EspNowPreferences.h>
#include <esp_crt_bundle.h>

#define SLEEP_TIME_US (1000LL * 1000LL * 60LL * 1LL) // 1 minute
#define MICROSECONDS_PER_SECOND 1000000LL
#define DEFAULT_SLEEP_TIME_US (MICROSECONDS_PER_SECOND * 60LL) // 60 seconds

#define FIRMWARE_VERSION 90201

// These structs are the application messages shared across the host and node device.
// These structs are the application messages shared across the host and node
// device.
#pragma pack(1)
struct MyApplicationMessage {
uint8_t id = 0x01;
Expand All @@ -18,6 +20,10 @@ struct MySecondApplicationMessage {
uint8_t id = 0x02;
double temperature;
};
struct MyConfigMessageV1 {
uint32_t sleep_seconds; // how long the node should deep-sleep
uint8_t foo; // some other config value, not used in this example
};
#pragma pack(0)

// Encyption key used for our own packet encryption (GCM).
Expand Down Expand Up @@ -61,7 +67,6 @@ EspNowNode::OnLog _on_log = [](const std::string message, const esp_log_level_t
level = "unknown";
break;
}

Serial.println(("EspNowNode (" + level + "): " + message).c_str());
};

Expand Down Expand Up @@ -96,14 +101,36 @@ void setup() {

_esp_now_preferences.initalizeNVS();

MyConfigMessageV1 configuration;
bool config_loaded = false;
if (_esp_now_preferences.getConfigData((uint8_t *)&configuration, (uint8_t)sizeof(MyConfigMessageV1))) {
config_loaded = true;
_on_log(("loaded sleep_seconds=" + std::to_string(configuration.sleep_seconds) +
" foo=" + std::to_string(configuration.foo))
.c_str(),
ESP_LOG_DEBUG);
} else {
_on_log("no config loaded", ESP_LOG_INFO);
}

// Setup node, send message, and then go to sleep.
if (_esp_now_node.setup()) {
MySecondApplicationMessage message;
message.temperature = 25.6;
_esp_now_node.sendMessage(&message, sizeof(MySecondApplicationMessage));
} else {
_on_log("setup failed", ESP_LOG_ERROR);
}

esp_deep_sleep(SLEEP_TIME_US);
uint32_t sleep_time_us = DEFAULT_SLEEP_TIME_US;
if (config_loaded) {
sleep_time_us = configuration.sleep_seconds * MICROSECONDS_PER_SECOND;
}

_on_log(("sleeping for " + std::to_string(sleep_time_us / (MICROSECONDS_PER_SECOND)) + " seconds").c_str(),
ESP_LOG_INFO);

esp_deep_sleep(sleep_time_us);
}

void loop() {}
void loop() {}
136 changes: 136 additions & 0 deletions examples/arduino/node_with_configuration/Node.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
#include <Arduino.h>
#include <EspNowCrypt.h>
#include <EspNowNode.h>
#include <EspNowPreferences.h>
#include <esp_crt_bundle.h>

#define MICROSECONDS_PER_SECOND 1000000LL
#define DEFAULT_SLEEP_TIME_US (MICROSECONDS_PER_SECOND * 60LL) // 60 seconds

#define FIRMWARE_VERSION 90201

// These structs are the application messages shared across the host and node
// device.
#pragma pack(1)
struct MyApplicationMessage {
uint8_t id = 0x01;
bool open;
};
struct MySecondApplicationMessage {
uint8_t id = 0x02;
double temperature;
};
struct MyConfigMessageV1 {
uint32_t sleep_seconds; // how long the node should deep-sleep
uint8_t foo; // some other config value, not used in this example
};
#pragma pack(0)

// Encyption key used for our own packet encryption (GCM).
// We are not using the esp-now encryption due to the peer limitation.
// The key should be the same for both the host and the node.
const char esp_now_encryption_key[] = "0123456789ABCDEF"; // Must be exact 16 bytes long. \0 does not count.

// Used to validate the integrity of the messages.
// The secret should be the same for both the host and the node.
const char esp_now_encryption_secret[] = "01234567"; // Must be exact 8 bytes long. \0 does not count.

unsigned long _turn_of_led_at_ms = 0;

EspNowNode::OnLog _on_log = [](const std::string message, const esp_log_level_t log_level) {
// Callback for logging. Can be omitted.
if (log_level == ESP_LOG_NONE) {
return; // Weird flex, but ok
}

std::string level;
switch (log_level) {
case ESP_LOG_NONE:
level = "none";
break;
case ESP_LOG_ERROR:
level = "error";
break;
case ESP_LOG_WARN:
level = "warning";
break;
case ESP_LOG_INFO:
level = "info";
break;
case ESP_LOG_DEBUG:
level = "debug";
break;
case ESP_LOG_VERBOSE:
level = "verbose";
break;
default:
level = "unknown";
break;
}
Serial.println(("EspNowNode (" + level + "): " + message).c_str());
};

EspNowNode::OnStatus _on_status = [](EspNowNode::Status status) {
switch (status) {
case EspNowNode::Status::HOST_DISCOVERY_STARTED:
break;
case EspNowNode::Status::HOST_DISCOVERY_SUCCESSFUL:
break;
case EspNowNode::Status::HOST_DISCOVERY_FAILED:
break;
case EspNowNode::Status::INVALID_HOST:
break;
case EspNowNode::Status::FIRMWARE_UPDATE_STARTED:
break;
case EspNowNode::Status::FIRMWARE_UPDATE_SUCCESSFUL:
break;
case EspNowNode::Status::FIRMWARE_UPDATE_FAILED:
break;
case EspNowNode::Status::FIRMWARE_UPDATE_WIFI_SETUP_FAILED:
break;
}
};

EspNowPreferences _esp_now_preferences;
EspNowCrypt _esp_now_crypt(esp_now_encryption_key, esp_now_encryption_secret);
EspNowNode _esp_now_node(_esp_now_crypt, _esp_now_preferences, FIRMWARE_VERSION, _on_status, _on_log,
arduino_esp_crt_bundle_attach);

void setup() {
Serial.begin(115200);

_esp_now_preferences.initalizeNVS();

MyConfigMessageV1 configuration;
bool config_loaded = false;
if (_esp_now_preferences.getConfigData((uint8_t *)&configuration, (uint8_t)sizeof(MyConfigMessageV1))) {
config_loaded = true;
_on_log(("loaded sleep_seconds=" + std::to_string(configuration.sleep_seconds) +
" foo=" + std::to_string(configuration.foo))
.c_str(),
ESP_LOG_DEBUG);
} else {
_on_log("no config loaded", ESP_LOG_INFO);
}

// Setup node, send message, and then go to sleep.
if (_esp_now_node.setup()) {
MySecondApplicationMessage message;
message.temperature = 25.6;
_esp_now_node.sendMessage(&message, sizeof(MySecondApplicationMessage));
} else {
_on_log("setup failed", ESP_LOG_ERROR);
}

uint32_t sleep_time_us = DEFAULT_SLEEP_TIME_US;
if (config_loaded) {
sleep_time_us = configuration.sleep_seconds * MICROSECONDS_PER_SECOND;
}

_on_log(("sleeping for " + std::to_string(sleep_time_us / (MICROSECONDS_PER_SECOND)) + " seconds").c_str(),
ESP_LOG_INFO);

esp_deep_sleep(sleep_time_us);
}

void loop() {}
Loading