Skip to content

Instantly share code, notes, and snippets.

@Tech500
Last active May 9, 2024 19:38
Show Gist options
  • Save Tech500/5fe5d6ca54cc50e0340ccd255c76c507 to your computer and use it in GitHub Desktop.
Save Tech500/5fe5d6ca54cc50e0340ccd255c76c507 to your computer and use it in GitHub Desktop.
Project RTC_DATA_ATTR not working; suspect deep sleep issue
//Modified for INA226 Voltage Monitor
//E220_Ticker_Test-Receiver.ino
//William Lucid 5/9/2024 @ 15:33 EST
//Corrections and No Ticker...
//Project uses ESP32 Devkit V1, INA226 Voltage Monitor, and KY002S MOSFET Switch
/*
* EBYTE LoRa E220-900T30D
* Stay in sleep mode and wait a wake up WOR message
*
* You must configure the address with 0 3 23 with WOR receiver enable
* and pay attention that WOR period must be the same of sender
*
*
* https://mischianti.org
*
* E32 ----- esp32
* M0 ----- 19 (or 3.3v)
* M1 ----- 21 (or GND)
* RX ----- TX2 (PullUP)
* TX ----- RX2 (PullUP)
* AUX ----- 15 (PullUP)
* VCC ----- 3.3v/5v
* GND ----- GND
*
*/
// with this DESTINATION_ADDL 2 you must set
// WOR SENDER configuration to the other device and
// WOR RECEIVER to this device
#define DESTINATION_ADDL 2
// If you want use RSSI uncomment //#define ENABLE_RSSI true
// and use relative configuration with RSSI enabled
//#define ENABLE_RSSI true
#include "Arduino.h"
//#include <Ticker.h>
#include "LoRa_E220.h"
#include <WiFi.h>
#include <time.h>
#include <FS.h>
#include <LittleFS.h>
#include "esp_system.h"
#include <esp_sleep.h>
#include "soc/rtc_cntl_reg.h"
#include "soc/rtc.h"
#include "driver/rtc_io.h"
#include <INA226_WE.h>
//const int analogPin = 34;
#define AUX GPIO_NUM_15 //WOR Radio/ESP32
#define TRIGGER 23 //INA226 Power Monitor
#define SWITCH 2 //KY002S Mosfet switch
#define relayPin 17 //remove?
//Ticker minuteTicker; // Ticker for counting every 60 seconds
/*
RTC_DATA_ATTR int totalElapsedMinutes = 0; // Counter for total elapsed minutes in RTC memory
// Flag to indicate if ticker is initialized
RTC_DATA_ATTR bool isTickerInitialized = false;
void incrementMinuteCounter() {
totalElapsedMinutes++; // Increment total elapsed minutes
Serial.print("Total elapsed minutes: ");
Serial.println(totalElapsedMinutes);
}
*/
void IRAM_ATTR underVoltageISR() {
Serial.print("Under-voltage alert after ");
//Serial.print(totalElapsedMinutes);
//Serial.println(" minutes.");
digitalWrite(TRIGGER, LOW); // Set a pin to LOW as an action on under-voltage
// Stop the ticker to avoid further updates
//minuteTicker.detach();
while (true) {
delay(1000); // Stay in an infinite loop to stop further code execution
}
}
#define I2C_ADDRESS 0x40
/* There are several ways to create your INA226 object:
* INA226_WE ina226 = INA226_WE(); -> uses I2C Address = 0x40 / Wire
* INA226_WE ina226 = INA226_WE(I2C_ADDRESS);
* INA226_WE ina226 = INA226_WE(&Wire); -> uses I2C_ADDRESS = 0x40, pass any Wire Object
* INA226_WE ina226 = INA226_WE(&Wire, I2C_ADDRESS);
*/
INA226_WE ina226 = INA226_WE(I2C_ADDRESS);
int interruptPin = 2;
volatile bool event = false;
void alert(){
event = true;
detachInterrupt(2);
}
int switchState; //initial swtchState
// Define the maximum length for the timestamp
const int MAX_TIMESTAMP_LENGTH = 30;
struct Message {
int switchState;
char timestamp[MAX_TIMESTAMP_LENGTH];
} message;
char dtStamp[MAX_TIMESTAMP_LENGTH];
#define FPM_SLEEP_MAX_TIME 0xFFFFFFF
void callback() {
Serial.println("Callback");
Serial.flush();
}
void printParameters(struct Configuration configuration);
// ---------- esp32 pins --------------
LoRa_E220 e220ttl(&Serial2, 15, 21, 19); // RX AUX M0 M1
//LoRa_E3220 e220ttl(&Serial2, 22, 4, 18, 21, 19, UART_BPS_RATE_9600); // esp32 RX <-- e22 TX, esp32 TX --> e22 RX AUX M0 M1
// -------------------------------------
int data;
// Persisted RTC variable
RTC_DATA_ATTR bool isPowerUp = false;
RTC_DATA_ATTR int bootCount = 0;
RTC_DATA_ATTR bool switch_State = false; // Initially switch is off
const int pulseDuration = 1000; // 100 milliseconds (adjust as needed)
bool interruptExecuted = false;
void IRAM_ATTR wakeUp() {
// Do not use Serial on interrupt callback
interruptExecuted = true;
detachInterrupt(AUX);
}
void printParameters(struct Configuration configuration);
void enterDeepSleep() {
gpio_hold_en(GPIO_NUM_19);
gpio_hold_en(GPIO_NUM_21);
esp_sleep_enable_ext0_wakeup(GPIO_NUM_15, LOW);
gpio_deep_sleep_hold_en();
Serial.println("Going to sleep now");
esp_deep_sleep_start();
delay(100);
Serial.println("This will never be printed");
}
void setup() {
Serial.begin(9600);
while(!Serial){}
Wire.begin(22, 18);
if(!ina226.init()){
Serial.println("Failed to init INA226. Check your wiring.");
//while(1){}
}
delay(1000);
/* Set Number of measurements for shunt and bus voltage which shall be averaged
* Mode * * Number of samples *
AVERAGE_1 1 (default)
AVERAGE_4 4
AVERAGE_16 16
AVERAGE_64 64
AVERAGE_128 128
AVERAGE_256 256
AVERAGE_512 512
AVERAGE_1024 1024
*/
// ina226.setAverage(AVERAGE_1024);
/* Set conversion time in microseconds
One set of shunt and bus voltage conversion will take:
number of samples to be averaged x conversion time x 2
* Mode * * conversion time *
CONV_TIME_140 140 µs
CONV_TIME_204 204 µs
CONV_TIME_332 332 µs
CONV_TIME_588 588 µs
CONV_TIME_1100 1.1 ms (default)
CONV_TIME_2116 2.116 ms
CONV_TIME_4156 4.156 ms
CONV_TIME_8244 8.244 ms
*/
// ina226.setConversionTime(CONV_TIME_8244);
/* Set measure mode
POWER_DOWN - INA226 switched off
TRIGGERED - measurement on demand
CONTINUOUS - continuous measurements (default)
*/
ina226.setMeasureMode(TRIGGERED); // choose mode and uncomment for change of default
/* If the current values delivered by the INA226 differ by a constant factor
from values obtained with calibrated equipment you can define a correction factor.
Correction factor = current delivered from calibrated equipment / current delivered by INA226
*/
// ina226.setCorrectionFactor(0.95);
/* In the default mode the limit interrupt flag will be deleted after the next measurement within limits.
With enableAltertLatch(), the flag will have to be deleted with readAndClearFlags().
*/
ina226.enableAlertLatch();
/* Set the alert type and the limit
* Mode * * Description * * limit unit *
SHUNT_OVER Shunt Voltage over limit mV
SHUNT_UNDER Shunt Voltage under limit mV
CURRENT_OVER Current over limit mA
CURRENT_UNDER Current under limit mA
BUS_OVER Bus Voltage over limit V
BUS_UNDER Bus Voltage under limit V
POWER_OVER Power over limit mW
*/
ina226.setAlertType(BUS_UNDER, 4.5);
attachInterrupt(digitalPinToInterrupt(SWITCH), alert, FALLING);
//Increment boot number and print it every reboot
++bootCount;
Serial.println("\n\nBoot number: " + String(bootCount));
if (isPowerUp) {
Serial.println("\nFlag indicates this was a deep sleep wake-up");
}
pinMode(AUX, OUTPUT); //ESP32 pin 15
pinMode(TRIGGER, OUTPUT); //ESP32 pin 23
pinMode(SWITCH, OUTPUT); //ESP32 pin 2
//pinMode(analogPin, INPUT);
delay(100);
bool fsok = LittleFS.begin(true);
Serial.printf_P(PSTR("\nFS init: %s\n"), fsok ? PSTR("ok") : PSTR("fail!"));
attachInterrupt(AUX, wakeUp, FALLING);
e220ttl.begin();
// After set configuration comment set M0 and M1 to low
// and reboot if you directly set HIGH M0 and M1 to program
ResponseStructContainer c;
c = e220ttl.getConfiguration();
Configuration configuration = *(Configuration*)c.data;
configuration.ADDL = 0x02;
configuration.ADDH = 0x00;
configuration.CHAN = 68;
configuration.SPED.uartBaudRate = UART_BPS_9600;
configuration.SPED.airDataRate = AIR_DATA_RATE_010_24;
configuration.SPED.uartParity = MODE_00_8N1;
configuration.OPTION.subPacketSetting = SPS_200_00;
configuration.OPTION.RSSIAmbientNoise = RSSI_AMBIENT_NOISE_DISABLED;
configuration.OPTION.transmissionPower = POWER_22;
configuration.TRANSMISSION_MODE.enableRSSI = RSSI_DISABLED;
configuration.TRANSMISSION_MODE.fixedTransmission = FT_FIXED_TRANSMISSION;
configuration.TRANSMISSION_MODE.enableLBT = LBT_DISABLED;
configuration.TRANSMISSION_MODE.WORPeriod = WOR_4000_111;
e220ttl.setConfiguration(configuration, WRITE_CFG_PWR_DWN_SAVE);
//printParameters(configuration);
c.close();
// ---------------------------
esp_sleep_wakeup_cause_t wakeup_reason;
wakeup_reason = esp_sleep_get_wakeup_cause();
if (ESP_SLEEP_WAKEUP_EXT0 == wakeup_reason) {
Serial.println("Waked up from external GPIO!");
gpio_hold_dis(GPIO_NUM_21);
gpio_hold_dis(GPIO_NUM_19);
gpio_deep_sleep_hold_dis();
e220ttl.setMode(MODE_0_NORMAL);
e220ttl.sendFixedMessage(0, DESTINATION_ADDL, 23, "We have waked up from message, but we can't read It!");
} else {
e220ttl.setMode(MODE_2_POWER_SAVING);
delay(1000);
Serial.println();
Serial.println("Start sleep!");
delay(100);
if (ESP_OK == gpio_hold_en(GPIO_NUM_21)) {
Serial.println("HOLD 21");
} else {
Serial.println("NO HOLD 21");
}
if (ESP_OK == gpio_hold_en(GPIO_NUM_19)) {
Serial.println("HOLD 19");
} else {
Serial.println("NO HOLD 19");
}
}
//e220ttl.setMode(MODE_0_NORMAL);
//delay(1000);
/*
// Check if ticker is initialized
if (!isTickerInitialized && totalElapsedMinutes < 1) {
// Initialize and set the flag
isTickerInitialized = true;
minuteTicker.attach(60, incrementMinuteCounter);
Serial.println("\nTicker initialized");
} else {
Serial.println("\nTicker already initialized");
}
//Serial.println("Waking up, minuteCounter: " + String(minuteCounter));
*/
int value = digitalRead(TRIGGER);
if(value == 1){
digitalWrite(TRIGGER, LOW);
}
Serial.println();
Serial.println("Wake and start listening!");
}
// The loop function is called in an endless loop
void loop() {
if (e220ttl.available() > 1) {
Serial.println("\nMessage arrived!");
ResponseStructContainer rsc = e220ttl.receiveMessage(sizeof(Message));
struct Message message = *(Message*)rsc.data;
delay(10);
Serial.print("TimeStamp: ");
Serial.println(message.timestamp);
Serial.print("\n\nSwitchState: ");
Serial.println(message.switchState);
free(rsc.data);
// Work only with full connection
e220ttl.setMode(MODE_0_NORMAL);
delay(10);
ResponseStatus rsSend = e220ttl.sendFixedMessage(0, DESTINATION_ADDL, 68, "We have received the message!");
// Check If there is some problem of succesfully send
Serial.println(rsSend.getResponseDescription());
if (interruptExecuted) {
Serial.println("WakeUp Callback, AUX pin go LOW and start receive message!\n");
if (message.switchState == 1) {
digitalWrite(relayPin, HIGH);
digitalWrite(TRIGGER, LOW);
delay(pulseDuration);
digitalWrite(TRIGGER, HIGH);
switch_State = digitalRead(TRIGGER); // Read current switch state
Serial.println("\nBattery power switched ON");
Serial.println("ESP32 wake from Deep Sleep\n");
char dtStamp[MAX_TIMESTAMP_LENGTH];
strncpy(dtStamp, message.timestamp, MAX_TIMESTAMP_LENGTH); // Copy timestamp
getINA226(dtStamp);
}
if (message.switchState == 2) {
digitalWrite(relayPin, LOW);
digitalWrite(TRIGGER, LOW);
switch_State = digitalRead(TRIGGER); // Read current switch state
Serial.println("\nBattery power switched OFF");
Serial.println("ESP32 going to Deep Sleep\n");
enterDeepSleep();
}
if(event){
ina226.readAndClearFlags(); // reads interrupt and overflow flags and deletes them
getINA226(dtStamp); //displayResults();
attachInterrupt(digitalPinToInterrupt(interruptPin), alert, FALLING);
event = false;
digitalWrite(TRIGGER, LOW);
Serial.println("Battery Alert 4.5 Volts");
Serial.print("Under-voltage alert after ");
//Serial.print(totalElapsedMinutes);
//Serial.println(" minutes.");
while(1){};
ina226.readAndClearFlags();
}
delay(1000);
}
}
}
int main() {
// Create an instance of the Message struct
Message message;
// Get the timestamp using the get_time function and assign it to the struct member
String timestamp = get_time();
timestamp.toCharArray(message.timestamp, MAX_TIMESTAMP_LENGTH);
// Now you can use message.timestamp as needed...
return 0;
}
// Function to get the timestamp
String get_time() {
time_t now;
time(&now);
char time_output[MAX_TIMESTAMP_LENGTH];
strftime(time_output, MAX_TIMESTAMP_LENGTH, "%a %d-%m-%y %T", localtime(&now));
return String(time_output); // returns timestamp in the specified format
}
void getINA226(const char* dtStamp) {
float shuntVoltage_mV = 0.0;
float loadVoltage_V = 0.0;
float busVoltage_V = 0.0;
float current_mA = 0.0;
float power_mW = 0.0;
ina226.startSingleMeasurement();
ina226.readAndClearFlags();
shuntVoltage_mV = ina226.getShuntVoltage_mV();
busVoltage_V = ina226.getBusVoltage_V();
current_mA = ina226.getCurrent_mA();
power_mW = ina226.getBusPower();
loadVoltage_V = busVoltage_V + (shuntVoltage_mV / 1000);
checkForI2cErrors();
Serial.println(dtStamp);
Serial.print("\nShunt Voltage [mV]: ");
Serial.println(shuntVoltage_mV);
Serial.print("Bus Voltage [V]: ");
Serial.println(busVoltage_V);
Serial.print("Load Voltage [V]: ");
Serial.println(loadVoltage_V);
Serial.print("Current[mA]: ");
Serial.println(current_mA);
Serial.print("Bus Power [mW]: ");
Serial.println(power_mW);
if (!ina226.overflow) {
Serial.println("Values OK - no overflow");
} else {
Serial.println("Overflow! Choose higher current range");
}
Serial.println();
// Open a "log.txt" for appended writing
File log = LittleFS.open("/log.txt", "a");
if (!log) {
Serial.println("file 'log.txt' open failed");
}
log.print(dtStamp);
log.print(" , ");
log.print(shuntVoltage_mV, 3);
log.print(" , ");
log.print(busVoltage_V, 3);
log.print(" , ");
log.print(loadVoltage_V, 3);
log.print(" , ");
log.print(current_mA, 3);
log.print(" , ");
log.print(power_mW, 3);
log.println("");
log.close();
}
void checkForI2cErrors() {
byte errorCode = ina226.getI2cErrorCode();
if (errorCode) {
Serial.print("I2C error: ");
Serial.println(errorCode);
switch (errorCode) {
case 1:
Serial.println("Data too long to fit in transmit buffer");
break;
case 2:
Serial.println("Received NACK on transmit of address");
break;
case 3:
Serial.println("Received NACK on transmit of data");
break;
case 4:
Serial.println("Other error");
break;
case 5:
Serial.println("Timeout");
break;
default:
Serial.println("Can't identify the error");
}
if (errorCode) {
while (1) {}
}
}
}
void printParameters(struct Configuration configuration) {
Serial.println("----------------------------------------");
Serial.print(F("HEAD : "));
Serial.print(configuration.COMMAND, HEX);
Serial.print(" ");
Serial.print(configuration.STARTING_ADDRESS, HEX);
Serial.print(" ");
Serial.println(configuration.LENGHT, HEX);
Serial.println(F(" "));
Serial.print(F("AddH : "));
Serial.println(configuration.ADDH, HEX);
Serial.print(F("AddL : "));
Serial.println(configuration.ADDL, HEX);
Serial.println(F(" "));
Serial.print(F("Chan : "));
Serial.print(configuration.CHAN, DEC);
Serial.print(" -> ");
Serial.println(configuration.getChannelDescription());
Serial.println(F(" "));
Serial.print(F("SpeedParityBit : "));
Serial.print(configuration.SPED.uartParity, BIN);
Serial.print(" -> ");
Serial.println(configuration.SPED.getUARTParityDescription());
Serial.print(F("SpeedUARTDatte : "));
Serial.print(configuration.SPED.uartBaudRate, BIN);
Serial.print(" -> ");
Serial.println(configuration.SPED.getUARTBaudRateDescription());
Serial.print(F("SpeedAirDataRate : "));
Serial.print(configuration.SPED.airDataRate, BIN);
Serial.print(" -> ");
Serial.println(configuration.SPED.getAirDataRateDescription());
Serial.println(F(" "));
Serial.print(F("OptionSubPacketSett: "));
Serial.print(configuration.OPTION.subPacketSetting, BIN);
Serial.print(" -> ");
Serial.println(configuration.OPTION.getSubPacketSetting());
Serial.print(F("OptionTranPower : "));
Serial.print(configuration.OPTION.transmissionPower, BIN);
Serial.print(" -> ");
Serial.println(configuration.OPTION.getTransmissionPowerDescription());
Serial.print(F("OptionRSSIAmbientNo: "));
Serial.print(configuration.OPTION.RSSIAmbientNoise, BIN);
Serial.print(" -> ");
Serial.println(configuration.OPTION.getRSSIAmbientNoiseEnable());
Serial.println(F(" "));
Serial.print(F("TransModeWORPeriod : "));
Serial.print(configuration.TRANSMISSION_MODE.WORPeriod, BIN);
Serial.print(" -> ");
Serial.println(configuration.TRANSMISSION_MODE.getWORPeriodByParamsDescription());
Serial.print(F("TransModeEnableLBT : "));
Serial.print(configuration.TRANSMISSION_MODE.enableLBT, BIN);
Serial.print(" -> ");
Serial.println(configuration.TRANSMISSION_MODE.getLBTEnableByteDescription());
Serial.print(F("TransModeEnableRSSI: "));
Serial.print(configuration.TRANSMISSION_MODE.enableRSSI, BIN);
Serial.print(" -> ");
Serial.println(configuration.TRANSMISSION_MODE.getRSSIEnableByteDescription());
Serial.print(F("TransModeFixedTrans: "));
Serial.print(configuration.TRANSMISSION_MODE.fixedTransmission, BIN);
Serial.print(" -> ");
Serial.println(configuration.TRANSMISSION_MODE.getFixedTransmissionDescription());
Serial.println("----------------------------------------");
}
void printModuleInformation(struct ModuleInformation moduleInformation) {
Serial.println("----------------------------------------");
Serial.print(F("HEAD: "));
Serial.print(moduleInformation.COMMAND, HEX);
Serial.print(" ");
Serial.print(moduleInformation.STARTING_ADDRESS, HEX);
Serial.print(" ");
Serial.println(moduleInformation.LENGHT, DEC);
Serial.print(F("Model no.: "));
Serial.println(moduleInformation.model, HEX);
Serial.print(F("Version : "));
Serial.println(moduleInformation.version, HEX);
Serial.print(F("Features : "));
Serial.println(moduleInformation.features, HEX);
Serial.println("----------------------------------------");
}
//Modified for INA226 Voltage Monitor
//E220_Ticker_Test-Receiver.ino
//William Lucid 5/9/2024 @ 15:17 EST
//Corrections; from last E220 Support Forum reply.
//Project uses ESP32 Devkit V1, INA226 Voltage Monitor, and KY002S MOSFET Switch
/*
* EBYTE LoRa E220-900T30D
* Stay in sleep mode and wait a wake up WOR message
*
* You must configure the address with 0 3 23 with WOR receiver enable
* and pay attention that WOR period must be the same of sender
*
*
* https://mischianti.org
*
* E32 ----- esp32
* M0 ----- 19 (or 3.3v)
* M1 ----- 21 (or GND)
* RX ----- TX2 (PullUP)
* TX ----- RX2 (PullUP)
* AUX ----- 15 (PullUP)
* VCC ----- 3.3v/5v
* GND ----- GND
*
*/
// with this DESTINATION_ADDL 2 you must set
// WOR SENDER configuration to the other device and
// WOR RECEIVER to this device
#define DESTINATION_ADDL 2
// If you want use RSSI uncomment //#define ENABLE_RSSI true
// and use relative configuration with RSSI enabled
//#define ENABLE_RSSI true
#include "Arduino.h"
#include <Ticker.h>
#include "LoRa_E220.h"
#include <WiFi.h>
#include <time.h>
#include <FS.h>
#include <LittleFS.h>
#include "esp_system.h"
#include <esp_sleep.h>
#include "soc/rtc_cntl_reg.h"
#include "soc/rtc.h"
#include "driver/rtc_io.h"
#include <INA226_WE.h>
//const int analogPin = 34;
#define AUX GPIO_NUM_15 //WOR Radio/ESP32
#define TRIGGER 23 //INA226 Power Monitor
#define SWITCH 2 //KY002S Mosfet switch
#define relayPin 17 //remove?
Ticker minuteTicker; // Ticker for counting every 60 seconds
RTC_DATA_ATTR int totalElapsedMinutes = 0; // Counter for total elapsed minutes in RTC memory
// Flag to indicate if ticker is initialized
RTC_DATA_ATTR bool isTickerInitialized = false;
void incrementMinuteCounter() {
totalElapsedMinutes++; // Increment total elapsed minutes
Serial.print("Total elapsed minutes: ");
Serial.println(totalElapsedMinutes);
}
void IRAM_ATTR underVoltageISR() {
Serial.print("Under-voltage alert after ");
Serial.print(totalElapsedMinutes);
Serial.println(" minutes.");
digitalWrite(TRIGGER, LOW); // Set a pin to LOW as an action on under-voltage
// Stop the ticker to avoid further updates
minuteTicker.detach();
while (true) {
delay(1000); // Stay in an infinite loop to stop further code execution
}
}
#define I2C_ADDRESS 0x40
/* There are several ways to create your INA226 object:
* INA226_WE ina226 = INA226_WE(); -> uses I2C Address = 0x40 / Wire
* INA226_WE ina226 = INA226_WE(I2C_ADDRESS);
* INA226_WE ina226 = INA226_WE(&Wire); -> uses I2C_ADDRESS = 0x40, pass any Wire Object
* INA226_WE ina226 = INA226_WE(&Wire, I2C_ADDRESS);
*/
INA226_WE ina226 = INA226_WE(I2C_ADDRESS);
int interruptPin = 2;
volatile bool event = false;
void alert(){
event = true;
detachInterrupt(2);
}
int switchState; //initial swtchState
// Define the maximum length for the timestamp
const int MAX_TIMESTAMP_LENGTH = 30;
struct Message {
int switchState;
char timestamp[MAX_TIMESTAMP_LENGTH];
} message;
char dtStamp[MAX_TIMESTAMP_LENGTH];
#define FPM_SLEEP_MAX_TIME 0xFFFFFFF
void callback() {
Serial.println("Callback");
Serial.flush();
}
void printParameters(struct Configuration configuration);
// ---------- esp32 pins --------------
LoRa_E220 e220ttl(&Serial2, 15, 21, 19); // RX AUX M0 M1
//LoRa_E3220 e220ttl(&Serial2, 22, 4, 18, 21, 19, UART_BPS_RATE_9600); // esp32 RX <-- e22 TX, esp32 TX --> e22 RX AUX M0 M1
// -------------------------------------
int data;
// Persisted RTC variable
RTC_DATA_ATTR bool isPowerUp = false;
RTC_DATA_ATTR int bootCount = 0;
RTC_DATA_ATTR bool switch_State = false; // Initially switch is off
const int pulseDuration = 1000; // 100 milliseconds (adjust as needed)
bool interruptExecuted = false;
void IRAM_ATTR wakeUp() {
// Do not use Serial on interrupt callback
interruptExecuted = true;
detachInterrupt(AUX);
}
void printParameters(struct Configuration configuration);
void enterDeepSleep() {
gpio_hold_en(GPIO_NUM_19);
gpio_hold_en(GPIO_NUM_21);
esp_sleep_enable_ext0_wakeup(GPIO_NUM_15, LOW);
gpio_deep_sleep_hold_en();
Serial.println("Going to sleep now");
esp_deep_sleep_start();
delay(100);
Serial.println("This will never be printed");
}
void setup() {
Serial.begin(9600);
while(!Serial){}
Wire.begin(22, 18);
if(!ina226.init()){
Serial.println("Failed to init INA226. Check your wiring.");
//while(1){}
}
delay(1000);
/* Set Number of measurements for shunt and bus voltage which shall be averaged
* Mode * * Number of samples *
AVERAGE_1 1 (default)
AVERAGE_4 4
AVERAGE_16 16
AVERAGE_64 64
AVERAGE_128 128
AVERAGE_256 256
AVERAGE_512 512
AVERAGE_1024 1024
*/
// ina226.setAverage(AVERAGE_1024);
/* Set conversion time in microseconds
One set of shunt and bus voltage conversion will take:
number of samples to be averaged x conversion time x 2
* Mode * * conversion time *
CONV_TIME_140 140 µs
CONV_TIME_204 204 µs
CONV_TIME_332 332 µs
CONV_TIME_588 588 µs
CONV_TIME_1100 1.1 ms (default)
CONV_TIME_2116 2.116 ms
CONV_TIME_4156 4.156 ms
CONV_TIME_8244 8.244 ms
*/
// ina226.setConversionTime(CONV_TIME_8244);
/* Set measure mode
POWER_DOWN - INA226 switched off
TRIGGERED - measurement on demand
CONTINUOUS - continuous measurements (default)
*/
ina226.setMeasureMode(TRIGGERED); // choose mode and uncomment for change of default
/* If the current values delivered by the INA226 differ by a constant factor
from values obtained with calibrated equipment you can define a correction factor.
Correction factor = current delivered from calibrated equipment / current delivered by INA226
*/
// ina226.setCorrectionFactor(0.95);
/* In the default mode the limit interrupt flag will be deleted after the next measurement within limits.
With enableAltertLatch(), the flag will have to be deleted with readAndClearFlags().
*/
ina226.enableAlertLatch();
/* Set the alert type and the limit
* Mode * * Description * * limit unit *
SHUNT_OVER Shunt Voltage over limit mV
SHUNT_UNDER Shunt Voltage under limit mV
CURRENT_OVER Current over limit mA
CURRENT_UNDER Current under limit mA
BUS_OVER Bus Voltage over limit V
BUS_UNDER Bus Voltage under limit V
POWER_OVER Power over limit mW
*/
ina226.setAlertType(BUS_UNDER, 4.5);
attachInterrupt(digitalPinToInterrupt(SWITCH), alert, FALLING);
//Increment boot number and print it every reboot
++bootCount;
Serial.println("\n\nBoot number: " + String(bootCount));
if (isPowerUp) {
Serial.println("\nFlag indicates this was a deep sleep wake-up");
}
pinMode(AUX, OUTPUT); //ESP32 pin 15
pinMode(TRIGGER, OUTPUT); //ESP32 pin 23
pinMode(SWITCH, OUTPUT); //ESP32 pin 2
//pinMode(analogPin, INPUT);
delay(100);
bool fsok = LittleFS.begin(true);
Serial.printf_P(PSTR("\nFS init: %s\n"), fsok ? PSTR("ok") : PSTR("fail!"));
attachInterrupt(AUX, wakeUp, FALLING);
e220ttl.begin();
// After set configuration comment set M0 and M1 to low
// and reboot if you directly set HIGH M0 and M1 to program
ResponseStructContainer c;
c = e220ttl.getConfiguration();
Configuration configuration = *(Configuration*)c.data;
configuration.ADDL = 0x02;
configuration.ADDH = 0x00;
configuration.CHAN = 68;
configuration.SPED.uartBaudRate = UART_BPS_9600;
configuration.SPED.airDataRate = AIR_DATA_RATE_010_24;
configuration.SPED.uartParity = MODE_00_8N1;
configuration.OPTION.subPacketSetting = SPS_200_00;
configuration.OPTION.RSSIAmbientNoise = RSSI_AMBIENT_NOISE_DISABLED;
configuration.OPTION.transmissionPower = POWER_22;
configuration.TRANSMISSION_MODE.enableRSSI = RSSI_DISABLED;
configuration.TRANSMISSION_MODE.fixedTransmission = FT_FIXED_TRANSMISSION;
configuration.TRANSMISSION_MODE.enableLBT = LBT_DISABLED;
configuration.TRANSMISSION_MODE.WORPeriod = WOR_4000_111;
e220ttl.setConfiguration(configuration, WRITE_CFG_PWR_DWN_SAVE);
//printParameters(configuration);
c.close();
// ---------------------------
esp_sleep_wakeup_cause_t wakeup_reason;
wakeup_reason = esp_sleep_get_wakeup_cause();
if (ESP_SLEEP_WAKEUP_EXT0 == wakeup_reason) {
Serial.println("Waked up from external GPIO!");
gpio_hold_dis(GPIO_NUM_21);
gpio_hold_dis(GPIO_NUM_19);
gpio_deep_sleep_hold_dis();
e220ttl.setMode(MODE_0_NORMAL);
e220ttl.sendFixedMessage(0, DESTINATION_ADDL, 23, "We have waked up from message, but we can't read It!");
} else {
e220ttl.setMode(MODE_2_POWER_SAVING);
delay(1000);
Serial.println();
Serial.println("Start sleep!");
delay(100);
if (ESP_OK == gpio_hold_en(GPIO_NUM_21)) {
Serial.println("HOLD 21");
} else {
Serial.println("NO HOLD 21");
}
if (ESP_OK == gpio_hold_en(GPIO_NUM_19)) {
Serial.println("HOLD 19");
} else {
Serial.println("NO HOLD 19");
}
}
//e220ttl.setMode(MODE_0_NORMAL);
//delay(1000);
// Check if ticker is initialized
if (!isTickerInitialized && totalElapsedMinutes < 1) {
// Initialize and set the flag
isTickerInitialized = true;
minuteTicker.attach(60, incrementMinuteCounter);
Serial.println("\nTicker initialized");
} else {
Serial.println("\nTicker already initialized");
}
//Serial.println("Waking up, minuteCounter: " + String(minuteCounter));
int value = digitalRead(TRIGGER);
if(value == 1){
digitalWrite(TRIGGER, LOW);
}
Serial.println();
Serial.println("Wake and start listening!");
}
// The loop function is called in an endless loop
void loop() {
if (e220ttl.available() > 1) {
Serial.println("\nMessage arrived!");
ResponseStructContainer rsc = e220ttl.receiveMessage(sizeof(Message));
struct Message message = *(Message*)rsc.data;
delay(10);
Serial.print("TimeStamp: ");
Serial.println(message.timestamp);
Serial.print("\n\nSwitchState: ");
Serial.println(message.switchState);
free(rsc.data);
// Work only with full connection
e220ttl.setMode(MODE_0_NORMAL);
delay(10);
ResponseStatus rsSend = e220ttl.sendFixedMessage(0, DESTINATION_ADDL, 68, "We have received the message!");
// Check If there is some problem of succesfully send
Serial.println(rsSend.getResponseDescription());
if (interruptExecuted) {
Serial.println("WakeUp Callback, AUX pin go LOW and start receive message!\n");
if (message.switchState == 1) {
digitalWrite(relayPin, HIGH);
digitalWrite(TRIGGER, LOW);
delay(pulseDuration);
digitalWrite(TRIGGER, HIGH);
switch_State = digitalRead(TRIGGER); // Read current switch state
Serial.println("\nBattery power switched ON");
Serial.println("ESP32 wake from Deep Sleep\n");
char dtStamp[MAX_TIMESTAMP_LENGTH];
strncpy(dtStamp, message.timestamp, MAX_TIMESTAMP_LENGTH); // Copy timestamp
getINA226(dtStamp);
}
if (message.switchState == 2) {
digitalWrite(relayPin, LOW);
digitalWrite(TRIGGER, LOW);
switch_State = digitalRead(TRIGGER); // Read current switch state
Serial.println("\nBattery power switched OFF");
Serial.println("ESP32 going to Deep Sleep\n");
enterDeepSleep();
}
if(event){
ina226.readAndClearFlags(); // reads interrupt and overflow flags and deletes them
//getINA226(dtStamp); //displayResults();
attachInterrupt(digitalPinToInterrupt(interruptPin), alert, FALLING);
event = false;
digitalWrite(TRIGGER, LOW);
Serial.println("Battery Alert 4.5 Volts");
Serial.print("Under-voltage alert after ");
Serial.print(totalElapsedMinutes);
Serial.println(" minutes.");
while(1){};
ina226.readAndClearFlags();
}
delay(1000);
}
}
}
int main() {
// Create an instance of the Message struct
Message message;
// Get the timestamp using the get_time function and assign it to the struct member
String timestamp = get_time();
timestamp.toCharArray(message.timestamp, MAX_TIMESTAMP_LENGTH);
// Now you can use message.timestamp as needed...
return 0;
}
// Function to get the timestamp
String get_time() {
time_t now;
time(&now);
char time_output[MAX_TIMESTAMP_LENGTH];
strftime(time_output, MAX_TIMESTAMP_LENGTH, "%a %d-%m-%y %T", localtime(&now));
return String(time_output); // returns timestamp in the specified format
}
void getINA226(const char* dtStamp) {
float shuntVoltage_mV = 0.0;
float loadVoltage_V = 0.0;
float busVoltage_V = 0.0;
float current_mA = 0.0;
float power_mW = 0.0;
ina226.startSingleMeasurement();
ina226.readAndClearFlags();
shuntVoltage_mV = ina226.getShuntVoltage_mV();
busVoltage_V = ina226.getBusVoltage_V();
current_mA = ina226.getCurrent_mA();
power_mW = ina226.getBusPower();
loadVoltage_V = busVoltage_V + (shuntVoltage_mV / 1000);
checkForI2cErrors();
Serial.println(dtStamp);
Serial.print("\nShunt Voltage [mV]: ");
Serial.println(shuntVoltage_mV);
Serial.print("Bus Voltage [V]: ");
Serial.println(busVoltage_V);
Serial.print("Load Voltage [V]: ");
Serial.println(loadVoltage_V);
Serial.print("Current[mA]: ");
Serial.println(current_mA);
Serial.print("Bus Power [mW]: ");
Serial.println(power_mW);
if (!ina226.overflow) {
Serial.println("Values OK - no overflow");
} else {
Serial.println("Overflow! Choose higher current range");
}
Serial.println();
// Open a "log.txt" for appended writing
File log = LittleFS.open("/log.txt", "a");
if (!log) {
Serial.println("file 'log.txt' open failed");
}
log.print(dtStamp);
log.print(" , ");
log.print(shuntVoltage_mV, 3);
log.print(" , ");
log.print(busVoltage_V, 3);
log.print(" , ");
log.print(loadVoltage_V, 3);
log.print(" , ");
log.print(current_mA, 3);
log.print(" , ");
log.print(power_mW, 3);
log.println("");
log.close();
}
void checkForI2cErrors() {
byte errorCode = ina226.getI2cErrorCode();
if (errorCode) {
Serial.print("I2C error: ");
Serial.println(errorCode);
switch (errorCode) {
case 1:
Serial.println("Data too long to fit in transmit buffer");
break;
case 2:
Serial.println("Received NACK on transmit of address");
break;
case 3:
Serial.println("Received NACK on transmit of data");
break;
case 4:
Serial.println("Other error");
break;
case 5:
Serial.println("Timeout");
break;
default:
Serial.println("Can't identify the error");
}
if (errorCode) {
while (1) {}
}
}
}
void printParameters(struct Configuration configuration) {
Serial.println("----------------------------------------");
Serial.print(F("HEAD : "));
Serial.print(configuration.COMMAND, HEX);
Serial.print(" ");
Serial.print(configuration.STARTING_ADDRESS, HEX);
Serial.print(" ");
Serial.println(configuration.LENGHT, HEX);
Serial.println(F(" "));
Serial.print(F("AddH : "));
Serial.println(configuration.ADDH, HEX);
Serial.print(F("AddL : "));
Serial.println(configuration.ADDL, HEX);
Serial.println(F(" "));
Serial.print(F("Chan : "));
Serial.print(configuration.CHAN, DEC);
Serial.print(" -> ");
Serial.println(configuration.getChannelDescription());
Serial.println(F(" "));
Serial.print(F("SpeedParityBit : "));
Serial.print(configuration.SPED.uartParity, BIN);
Serial.print(" -> ");
Serial.println(configuration.SPED.getUARTParityDescription());
Serial.print(F("SpeedUARTDatte : "));
Serial.print(configuration.SPED.uartBaudRate, BIN);
Serial.print(" -> ");
Serial.println(configuration.SPED.getUARTBaudRateDescription());
Serial.print(F("SpeedAirDataRate : "));
Serial.print(configuration.SPED.airDataRate, BIN);
Serial.print(" -> ");
Serial.println(configuration.SPED.getAirDataRateDescription());
Serial.println(F(" "));
Serial.print(F("OptionSubPacketSett: "));
Serial.print(configuration.OPTION.subPacketSetting, BIN);
Serial.print(" -> ");
Serial.println(configuration.OPTION.getSubPacketSetting());
Serial.print(F("OptionTranPower : "));
Serial.print(configuration.OPTION.transmissionPower, BIN);
Serial.print(" -> ");
Serial.println(configuration.OPTION.getTransmissionPowerDescription());
Serial.print(F("OptionRSSIAmbientNo: "));
Serial.print(configuration.OPTION.RSSIAmbientNoise, BIN);
Serial.print(" -> ");
Serial.println(configuration.OPTION.getRSSIAmbientNoiseEnable());
Serial.println(F(" "));
Serial.print(F("TransModeWORPeriod : "));
Serial.print(configuration.TRANSMISSION_MODE.WORPeriod, BIN);
Serial.print(" -> ");
Serial.println(configuration.TRANSMISSION_MODE.getWORPeriodByParamsDescription());
Serial.print(F("TransModeEnableLBT : "));
Serial.print(configuration.TRANSMISSION_MODE.enableLBT, BIN);
Serial.print(" -> ");
Serial.println(configuration.TRANSMISSION_MODE.getLBTEnableByteDescription());
Serial.print(F("TransModeEnableRSSI: "));
Serial.print(configuration.TRANSMISSION_MODE.enableRSSI, BIN);
Serial.print(" -> ");
Serial.println(configuration.TRANSMISSION_MODE.getRSSIEnableByteDescription());
Serial.print(F("TransModeFixedTrans: "));
Serial.print(configuration.TRANSMISSION_MODE.fixedTransmission, BIN);
Serial.print(" -> ");
Serial.println(configuration.TRANSMISSION_MODE.getFixedTransmissionDescription());
Serial.println("----------------------------------------");
}
void printModuleInformation(struct ModuleInformation moduleInformation) {
Serial.println("----------------------------------------");
Serial.print(F("HEAD: "));
Serial.print(moduleInformation.COMMAND, HEX);
Serial.print(" ");
Serial.print(moduleInformation.STARTING_ADDRESS, HEX);
Serial.print(" ");
Serial.println(moduleInformation.LENGHT, DEC);
Serial.print(F("Model no.: "));
Serial.println(moduleInformation.model, HEX);
Serial.print(F("Version : "));
Serial.println(moduleInformation.version, HEX);
Serial.print(F("Features : "));
Serial.println(moduleInformation.features, HEX);
Serial.println("----------------------------------------");
}
//Modified for INA226 Voltage Monitor
//E220_Ticker_Test-Receiver.ino
//William Lucid 5/5/2024 @ 21:08 EST
//Project uses ESP32 Devkit V1, INA226 Voltage Monitor, and KY002S MOSFET Switch
/*
* EBYTE LoRa E220-900T30D
* Stay in sleep mode and wait a wake up WOR message
*
* You must configure the address with 0 3 23 with WOR receiver enable
* and pay attention that WOR period must be the same of sender
*
*
* https://mischianti.org
*
* E32 ----- esp32
* M0 ----- 19 (or 3.3v)
* M1 ----- 21 (or GND)
* RX ----- TX2 (PullUP)
* TX ----- RX2 (PullUP)
* AUX ----- 15 (PullUP)
* VCC ----- 3.3v/5v
* GND ----- GND
*
*/
// with this DESTINATION_ADDL 2 you must set
// WOR SENDER configuration to the other device and
// WOR RECEIVER to this device
#define DESTINATION_ADDL 2
// If you want use RSSI uncomment //#define ENABLE_RSSI true
// and use relative configuration with RSSI enabled
//#define ENABLE_RSSI true
#include "Arduino.h"
#include <Ticker.h>
#include "LoRa_E220.h"
#include <WiFi.h>
#include <time.h>
#include <FS.h>
#include <LittleFS.h>
#include "esp_system.h"
#include <esp_sleep.h>
#include "soc/rtc_cntl_reg.h"
#include "soc/rtc.h"
#include "driver/rtc_io.h"
#include <INA226_WE.h>
Ticker minuteTicker; // Ticker for counting every 60 seconds
RTC_DATA_ATTR int totalElapsedMinutes = 0; // Counter for total elapsed minutes in RTC memory
// Flag to indicate if ticker is initialized
RTC_DATA_ATTR bool isTickerInitialized = false;
void incrementMinuteCounter() {
totalElapsedMinutes++; // Increment total elapsed minutes
Serial.print("Total elapsed minutes: ");
Serial.println(totalElapsedMinutes);
}
void IRAM_ATTR underVoltageISR() {
Serial.print("Under-voltage alert after ");
Serial.print(totalElapsedMinutes);
Serial.println(" minutes.");
digitalWrite(23, LOW); // Set a pin to LOW as an action on under-voltage
// Stop the ticker to avoid further updates
minuteTicker.detach();
while (true) {
delay(1000); // Stay in an infinite loop to stop further code execution
}
}
#define I2C_ADDRESS 0x40
/* There are several ways to create your INA226 object:
* INA226_WE ina226 = INA226_WE(); -> uses I2C Address = 0x40 / Wire
* INA226_WE ina226 = INA226_WE(I2C_ADDRESS);
* INA226_WE ina226 = INA226_WE(&Wire); -> uses I2C_ADDRESS = 0x40, pass any Wire Object
* INA226_WE ina226 = INA226_WE(&Wire, I2C_ADDRESS);
*/
INA226_WE ina226 = INA226_WE(I2C_ADDRESS);
int interruptPin = 2;
volatile bool event = false;
void alert(){
event = true;
detachInterrupt(2);
}
//const int analogPin = 34;
#define AUX GPIO_NUM_15
#define relayPin 17
int switchState; //initial swtchState
// Define the maximum length for the timestamp
const int MAX_TIMESTAMP_LENGTH = 30;
struct Message {
int switchState;
char timestamp[MAX_TIMESTAMP_LENGTH];
} message;
char dtStamp[MAX_TIMESTAMP_LENGTH];
#define FPM_SLEEP_MAX_TIME 0xFFFFFFF
void callback() {
Serial.println("Callback");
Serial.flush();
}
void printParameters(struct Configuration configuration);
// ---------- esp32 pins --------------
LoRa_E220 e32ttl(&Serial2, 15, 21, 19); // RX AUX M0 M1
//LoRa_E3220 e32ttl(&Serial2, 22, 4, 18, 21, 19, UART_BPS_RATE_9600); // esp32 RX <-- e22 TX, esp32 TX --> e22 RX AUX M0 M1
// -------------------------------------
int data;
// Persisted RTC variable
RTC_DATA_ATTR bool isPowerUp = false;
RTC_DATA_ATTR int bootCount = 0;
RTC_DATA_ATTR bool switch_State = false; // Initially switch is off
const int pulseDuration = 1000; // 100 milliseconds (adjust as needed)
bool interruptExecuted = false;
void IRAM_ATTR wakeUp() {
// Do not use Serial on interrupt callback
interruptExecuted = true;
detachInterrupt(AUX);
}
void printParameters(struct Configuration configuration);
// ---------- esp32 pins --------------
LoRa_E220 e220ttl(&Serial2, 15, 21, 19); // RX AUX M0 M1
//LoRa_E32 e220ttl(&Serial2, 22, 4, 18, 21, 19, UART_BPS_RATE_9600); // esp32 RX <-- e22 TX, esp32 TX --> e22 RX AUX M0 M1
// -------------------------------------
void enterDeepSleep() {
gpio_hold_en(GPIO_NUM_19);
gpio_hold_en(GPIO_NUM_21);
//gpio_hold_en(GPIO_NUM_23);
esp_sleep_enable_ext0_wakeup(GPIO_NUM_15, LOW);
gpio_deep_sleep_hold_en();
Serial.println("Going to sleep now");
esp_deep_sleep_start();
delay(100);
Serial.println("This will never be printed");
}
void setup() {
Serial.begin(9600);
while(!Serial){}
Wire.begin(22, 18);
if(!ina226.init()){
Serial.println("Failed to init INA226. Check your wiring.");
//while(1){}
}
delay(1000);
/* Set Number of measurements for shunt and bus voltage which shall be averaged
* Mode * * Number of samples *
AVERAGE_1 1 (default)
AVERAGE_4 4
AVERAGE_16 16
AVERAGE_64 64
AVERAGE_128 128
AVERAGE_256 256
AVERAGE_512 512
AVERAGE_1024 1024
*/
// ina226.setAverage(AVERAGE_1024);
/* Set conversion time in microseconds
One set of shunt and bus voltage conversion will take:
number of samples to be averaged x conversion time x 2
* Mode * * conversion time *
CONV_TIME_140 140 µs
CONV_TIME_204 204 µs
CONV_TIME_332 332 µs
CONV_TIME_588 588 µs
CONV_TIME_1100 1.1 ms (default)
CONV_TIME_2116 2.116 ms
CONV_TIME_4156 4.156 ms
CONV_TIME_8244 8.244 ms
*/
// ina226.setConversionTime(CONV_TIME_8244);
/* Set measure mode
POWER_DOWN - INA226 switched off
TRIGGERED - measurement on demand
CONTINUOUS - continuous measurements (default)
*/
ina226.setMeasureMode(TRIGGERED); // choose mode and uncomment for change of default
/* If the current values delivered by the INA226 differ by a constant factor
from values obtained with calibrated equipment you can define a correction factor.
Correction factor = current delivered from calibrated equipment / current delivered by INA226
*/
// ina226.setCorrectionFactor(0.95);
/* In the default mode the limit interrupt flag will be deleted after the next measurement within limits.
With enableAltertLatch(), the flag will have to be deleted with readAndClearFlags().
*/
ina226.enableAlertLatch();
/* Set the alert type and the limit
* Mode * * Description * * limit unit *
SHUNT_OVER Shunt Voltage over limit mV
SHUNT_UNDER Shunt Voltage under limit mV
CURRENT_OVER Current over limit mA
CURRENT_UNDER Current under limit mA
BUS_OVER Bus Voltage over limit V
BUS_UNDER Bus Voltage under limit V
POWER_OVER Power over limit mW
*/
ina226.setAlertType(BUS_UNDER, 4.5);
attachInterrupt(digitalPinToInterrupt(interruptPin), alert, FALLING);
//Increment boot number and print it every reboot
++bootCount;
Serial.println("\n\nBoot number: " + String(bootCount));
if (isPowerUp) {
Serial.println("\nFlag indicates this was a deep sleep wake-up");
}
pinMode(23, OUTPUT);
//pinMode(analogPin, INPUT);
delay(100);
bool fsok = LittleFS.begin(true);
Serial.printf_P(PSTR("\nFS init: %s\n"), fsok ? PSTR("ok") : PSTR("fail!"));
attachInterrupt(AUX, wakeUp, FALLING);
e220ttl.begin();
// After set configuration comment set M0 and M1 to low
// and reboot if you directly set HIGH M0 and M1 to program
ResponseStructContainer c;
c = e220ttl.getConfiguration();
Configuration configuration = *(Configuration*)c.data;
configuration.ADDL = 0x02;
configuration.ADDH = 0x00;
configuration.CHAN = 68;
configuration.SPED.uartBaudRate = UART_BPS_9600;
configuration.SPED.airDataRate = AIR_DATA_RATE_010_24;
configuration.SPED.uartParity = MODE_00_8N1;
configuration.OPTION.subPacketSetting = SPS_200_00;
configuration.OPTION.RSSIAmbientNoise = RSSI_AMBIENT_NOISE_DISABLED;
configuration.OPTION.transmissionPower = POWER_22;
configuration.TRANSMISSION_MODE.enableRSSI = RSSI_DISABLED;
configuration.TRANSMISSION_MODE.fixedTransmission = FT_FIXED_TRANSMISSION;
configuration.TRANSMISSION_MODE.enableLBT = LBT_DISABLED;
configuration.TRANSMISSION_MODE.WORPeriod = WOR_4000_111;
e220ttl.setConfiguration(configuration, WRITE_CFG_PWR_DWN_SAVE);
//printParameters(configuration);
c.close();
// ---------------------------
esp_sleep_wakeup_cause_t wakeup_reason;
wakeup_reason = esp_sleep_get_wakeup_cause();
if (ESP_SLEEP_WAKEUP_EXT0 == wakeup_reason) {
Serial.println("Waked up from external GPIO!");
gpio_hold_dis(GPIO_NUM_21);
gpio_hold_dis(GPIO_NUM_19);
gpio_deep_sleep_hold_dis();
e32ttl.setMode(MODE_0_NORMAL);
e32ttl.sendFixedMessage(0, DESTINATION_ADDL, 23, "We have waked up from message, but we can't read It!");
} else {
e32ttl.setMode(MODE_2_POWER_SAVING);
delay(1000);
Serial.println();
Serial.println("Start sleep!");
delay(100);
if (ESP_OK == gpio_hold_en(GPIO_NUM_21)) {
Serial.println("HOLD 21");
} else {
Serial.println("NO HOLD 21");
}
if (ESP_OK == gpio_hold_en(GPIO_NUM_19)) {
Serial.println("HOLD 19");
} else {
Serial.println("NO HOLD 19");
}
}
//e32ttl.setMode(MODE_0_NORMAL);
//delay(1000);
// Check if ticker is initialized
if (!isTickerInitialized && totalElapsedMinutes < 1) {
// Initialize and set the flag
isTickerInitialized = true;
minuteTicker.attach(60, incrementMinuteCounter);
Serial.println("\nTicker initialized");
} else {
Serial.println("\nTicker already initialized");
}
//Serial.println("Waking up, minuteCounter: " + String(minuteCounter));
int value = digitalRead(23);
if(value == 1){
digitalWrite(23, LOW);
}
Serial.println();
Serial.println("Wake and start listening!");
}
// The loop function is called in an endless loop
void loop() {
if (e220ttl.available() > 1) {
Serial.println("\nMessage arrived!");
ResponseStructContainer rsc = e220ttl.receiveMessage(sizeof(Message));
struct Message message = *(Message*)rsc.data;
delay(10);
Serial.print("TimeStamp: ");
Serial.println(message.timestamp);
Serial.print("\n\nSwitchState: ");
Serial.println(message.switchState);
free(rsc.data);
// Work only with full connection
e220ttl.setMode(MODE_0_NORMAL);
delay(10);
ResponseStatus rsSend = e220ttl.sendFixedMessage(0, DESTINATION_ADDL, 68, "We have received the message!");
// Check If there is some problem of succesfully send
Serial.println(rsSend.getResponseDescription());
if (interruptExecuted) {
Serial.println("WakeUp Callback, AUX pin go LOW and start receive message!\n");
if (message.switchState == 1) {
digitalWrite(relayPin, HIGH);
digitalWrite(23, LOW);
delay(pulseDuration);
digitalWrite(23, HIGH);
switch_State = digitalRead(23); // Read current switch state
Serial.println("\nBattery power switched ON");
Serial.println("ESP32 wake from Deep Sleep\n");
char dtStamp[MAX_TIMESTAMP_LENGTH];
strncpy(dtStamp, message.timestamp, MAX_TIMESTAMP_LENGTH); // Copy timestamp
getINA226(dtStamp);
}
if (message.switchState == 2) {
digitalWrite(relayPin, LOW);
digitalWrite(23, LOW);
switch_State = digitalRead(23); // Read current switch state
Serial.println("\nBattery power switched OFF");
Serial.println("ESP32 going to Deep Sleep\n");
enterDeepSleep();
}
if(event){
ina226.readAndClearFlags(); // reads interrupt and overflow flags and deletes them
//getINA226(dtStamp); //displayResults();
attachInterrupt(digitalPinToInterrupt(interruptPin), alert, FALLING);
event = false;
digitalWrite(23, LOW);
Serial.println("Battery Alert 4.5 Volts");
Serial.print("Under-voltage alert after ");
Serial.print(totalElapsedMinutes);
Serial.println(" minutes.");
while(1){};
ina226.readAndClearFlags();
}
delay(1000);
}
}
}
int main() {
// Create an instance of the Message struct
Message message;
// Get the timestamp using the get_time function and assign it to the struct member
String timestamp = get_time();
timestamp.toCharArray(message.timestamp, MAX_TIMESTAMP_LENGTH);
// Now you can use message.timestamp as needed...
return 0;
}
// Function to get the timestamp
String get_time() {
time_t now;
time(&now);
char time_output[MAX_TIMESTAMP_LENGTH];
strftime(time_output, MAX_TIMESTAMP_LENGTH, "%a %d-%m-%y %T", localtime(&now));
return String(time_output); // returns timestamp in the specified format
}
void getINA226(const char* dtStamp) {
float shuntVoltage_mV = 0.0;
float loadVoltage_V = 0.0;
float busVoltage_V = 0.0;
float current_mA = 0.0;
float power_mW = 0.0;
ina226.startSingleMeasurement();
ina226.readAndClearFlags();
shuntVoltage_mV = ina226.getShuntVoltage_mV();
busVoltage_V = ina226.getBusVoltage_V();
current_mA = ina226.getCurrent_mA();
power_mW = ina226.getBusPower();
loadVoltage_V = busVoltage_V + (shuntVoltage_mV / 1000);
checkForI2cErrors();
Serial.println(dtStamp);
Serial.print("\nShunt Voltage [mV]: ");
Serial.println(shuntVoltage_mV);
Serial.print("Bus Voltage [V]: ");
Serial.println(busVoltage_V);
Serial.print("Load Voltage [V]: ");
Serial.println(loadVoltage_V);
Serial.print("Current[mA]: ");
Serial.println(current_mA);
Serial.print("Bus Power [mW]: ");
Serial.println(power_mW);
if (!ina226.overflow) {
Serial.println("Values OK - no overflow");
} else {
Serial.println("Overflow! Choose higher current range");
}
Serial.println();
// Open a "log.txt" for appended writing
File log = LittleFS.open("/log.txt", "a");
if (!log) {
Serial.println("file 'log.txt' open failed");
}
log.print(dtStamp);
log.print(" , ");
log.print(shuntVoltage_mV, 3);
log.print(" , ");
log.print(busVoltage_V, 3);
log.print(" , ");
log.print(loadVoltage_V, 3);
log.print(" , ");
log.print(current_mA, 3);
log.print(" , ");
log.print(power_mW, 3);
log.println("");
log.close();
}
void checkForI2cErrors() {
byte errorCode = ina226.getI2cErrorCode();
if (errorCode) {
Serial.print("I2C error: ");
Serial.println(errorCode);
switch (errorCode) {
case 1:
Serial.println("Data too long to fit in transmit buffer");
break;
case 2:
Serial.println("Received NACK on transmit of address");
break;
case 3:
Serial.println("Received NACK on transmit of data");
break;
case 4:
Serial.println("Other error");
break;
case 5:
Serial.println("Timeout");
break;
default:
Serial.println("Can't identify the error");
}
if (errorCode) {
while (1) {}
}
}
}
void printParameters(struct Configuration configuration) {
Serial.println("----------------------------------------");
Serial.print(F("HEAD : "));
Serial.print(configuration.COMMAND, HEX);
Serial.print(" ");
Serial.print(configuration.STARTING_ADDRESS, HEX);
Serial.print(" ");
Serial.println(configuration.LENGHT, HEX);
Serial.println(F(" "));
Serial.print(F("AddH : "));
Serial.println(configuration.ADDH, HEX);
Serial.print(F("AddL : "));
Serial.println(configuration.ADDL, HEX);
Serial.println(F(" "));
Serial.print(F("Chan : "));
Serial.print(configuration.CHAN, DEC);
Serial.print(" -> ");
Serial.println(configuration.getChannelDescription());
Serial.println(F(" "));
Serial.print(F("SpeedParityBit : "));
Serial.print(configuration.SPED.uartParity, BIN);
Serial.print(" -> ");
Serial.println(configuration.SPED.getUARTParityDescription());
Serial.print(F("SpeedUARTDatte : "));
Serial.print(configuration.SPED.uartBaudRate, BIN);
Serial.print(" -> ");
Serial.println(configuration.SPED.getUARTBaudRateDescription());
Serial.print(F("SpeedAirDataRate : "));
Serial.print(configuration.SPED.airDataRate, BIN);
Serial.print(" -> ");
Serial.println(configuration.SPED.getAirDataRateDescription());
Serial.println(F(" "));
Serial.print(F("OptionSubPacketSett: "));
Serial.print(configuration.OPTION.subPacketSetting, BIN);
Serial.print(" -> ");
Serial.println(configuration.OPTION.getSubPacketSetting());
Serial.print(F("OptionTranPower : "));
Serial.print(configuration.OPTION.transmissionPower, BIN);
Serial.print(" -> ");
Serial.println(configuration.OPTION.getTransmissionPowerDescription());
Serial.print(F("OptionRSSIAmbientNo: "));
Serial.print(configuration.OPTION.RSSIAmbientNoise, BIN);
Serial.print(" -> ");
Serial.println(configuration.OPTION.getRSSIAmbientNoiseEnable());
Serial.println(F(" "));
Serial.print(F("TransModeWORPeriod : "));
Serial.print(configuration.TRANSMISSION_MODE.WORPeriod, BIN);
Serial.print(" -> ");
Serial.println(configuration.TRANSMISSION_MODE.getWORPeriodByParamsDescription());
Serial.print(F("TransModeEnableLBT : "));
Serial.print(configuration.TRANSMISSION_MODE.enableLBT, BIN);
Serial.print(" -> ");
Serial.println(configuration.TRANSMISSION_MODE.getLBTEnableByteDescription());
Serial.print(F("TransModeEnableRSSI: "));
Serial.print(configuration.TRANSMISSION_MODE.enableRSSI, BIN);
Serial.print(" -> ");
Serial.println(configuration.TRANSMISSION_MODE.getRSSIEnableByteDescription());
Serial.print(F("TransModeFixedTrans: "));
Serial.print(configuration.TRANSMISSION_MODE.fixedTransmission, BIN);
Serial.print(" -> ");
Serial.println(configuration.TRANSMISSION_MODE.getFixedTransmissionDescription());
Serial.println("----------------------------------------");
}
void printModuleInformation(struct ModuleInformation moduleInformation) {
Serial.println("----------------------------------------");
Serial.print(F("HEAD: "));
Serial.print(moduleInformation.COMMAND, HEX);
Serial.print(" ");
Serial.print(moduleInformation.STARTING_ADDRESS, HEX);
Serial.print(" ");
Serial.println(moduleInformation.LENGHT, DEC);
Serial.print(F("Model no.: "));
Serial.println(moduleInformation.model, HEX);
Serial.print(F("Version : "));
Serial.println(moduleInformation.version, HEX);
Serial.print(F("Features : "));
Serial.println(moduleInformation.features, HEX);
Serial.println("----------------------------------------");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment