Skip to content

Instantly share code, notes, and snippets.

@Tech500
Last active June 27, 2024 19:59
Show Gist options
  • Save Tech500/f53de2636bc1589779394360931c3a00 to your computer and use it in GitHub Desktop.
Save Tech500/f53de2636bc1589779394360931c3a00 to your computer and use it in GitHub Desktop.
Two, e220-900T30D transceivers project for controlling a remote battery switch.
// E220_Structure_Receiver.ino
// 06/27/2024 13:22 EST
// Receiver not receiving meesages; only message occurs on ESP32 press of reet switch.
#include "Arduino.h"
#include "LoRa_E220.h"
#include <WiFi.h>
#include <time.h>
#include <FS.h>
#include <LittleFS.h>
#include "esp_sleep.h"
#include "driver/gpio.h"
#include "esp_system.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/rtc.h"
#include "driver/rtc_io.h"
#include <INA226_WE.h>
#include <Wire.h>
#define FREQUENCY_915
#define CHANNEL 66
#define AUX_PIN_BITMASK 0x8000
#define DESTINATION_ADDL 2
#define AUX_PIN GPIO_NUM_15
#define TRIGGER 23 // KY002S MOSFET Bi-Stable Switch
#define ALERT 4 // INA226 Battery Monitor
#define SDA 13
#define SCL 22
#define RXD1 16
#define TXD1 17
#define I2C_ADDRESS 0x40
RTC_DATA_ATTR int bootCount = 0;
int delayTime = 1000; //setMode delay
int pulseDuration(100);
int switch_State; //trigger duration
INA226_WE ina226 = INA226_WE(I2C_ADDRESS);
volatile bool event = false;
void alert() {
event = true;
detachInterrupt(ALERT);
}
struct DateTime {
int year;
int month;
int day;
int hour;
int minute;
int second;
};
//char dtStamp[MAX_TIMESTAMP_LENGTH];
const int MAX_TIMESTAMP_LENGTH = 30;
struct Message {
int switchState;
char timestamp[MAX_TIMESTAMP_LENGTH];
};
Message message;
volatile int data = message.switchState;
#define FPM_SLEEP_MAX_TIME 0xFFFFFFF
void callback() {
Serial.println("Callback");
Serial.flush();
}
bool interruptExecuted = false;
void IRAM_ATTR wakeUp() {
interruptExecuted = true;
detachInterrupt(AUX_PIN);
}
void printParameters(struct Configuration configuration);
LoRa_E220 e220ttl(&Serial2, 15, 21, 19);
void handleWakeupReason() {
esp_sleep_wakeup_cause_t wakeup_reason = esp_sleep_get_wakeup_cause();
switch (wakeup_reason) {
case ESP_SLEEP_WAKEUP_EXT0:
Serial.println("Wakeup caused by external signal using RTC_IO");
break;
case ESP_SLEEP_WAKEUP_EXT1:
Serial.println("Wakeup caused by external signal using RTC_CNTL");
break;
case ESP_SLEEP_WAKEUP_TIMER:
Serial.println("Wakeup caused by timer");
break;
case ESP_SLEEP_WAKEUP_TOUCHPAD:
Serial.println("Wakeup caused by touchpad");
break;
case ESP_SLEEP_WAKEUP_ULP:
Serial.println("Wakeup caused by ULP program");
break;
default:
Serial.printf("Wakeup was not caused by deep sleep: %d\n", wakeup_reason);
break;
}
}
void enterDeepSleep() {
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_SLOW_MEM, ESP_PD_OPTION_ON);
gpio_hold_en(GPIO_NUM_19);
gpio_hold_en(GPIO_NUM_21);
gpio_deep_sleep_hold_en();
esp_sleep_enable_ext0_wakeup(GPIO_NUM_15, 0); // Ensure AUX_PIN wakes up ESP32
Serial.println("Going to sleep now");
Serial.flush();
esp_deep_sleep_start();
Serial.println("This will never be printed");
}
void setup() {
Serial.begin(9600);
delay(1000);
Serial1.begin(9600, SERIAL_8N1, RXD1, TXD1);
delay(500);
gpio_deep_sleep_hold_dis();
e220ttl.setMode(MODE_0_NORMAL);
delay(delayTime);
Serial.println("\n\nE220 Remote Switch Receiver\n");
Wire.begin(SDA, SCL);
//Increment boot number and print it every reboot
++bootCount;
Serial.println("Boot number: " + String(bootCount));
esp_sleep_enable_ext0_wakeup(GPIO_NUM_15, 0);
pinMode(AUX_PIN, INPUT_PULLUP);
pinMode(TRIGGER, OUTPUT); // ESP32, GPIO23
pinMode(ALERT, OUTPUT); // ESP32, GPIO4
attachInterrupt(digitalPinToInterrupt(GPIO_NUM_15), wakeUp, LOW);
bool fsok = LittleFS.begin(true);
Serial.printf_P(PSTR("\nFS init: %s\n"), fsok ? PSTR("ok") : PSTR("fail!"));
e220ttl.begin();
e220ttl.setMode(MODE_2_WOR_RECEIVER);
//handleWakeupReason();
esp_sleep_wakeup_cause_t wakeup_reason = esp_sleep_get_wakeup_cause();
if (wakeup_reason == esp_sleep_get_wakeup_cause()) {
//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);
delay(delayTime);
e220ttl.sendFixedMessage(0, DESTINATION_ADDL, CHANNEL, "We have waked up from message, but we can't read It!");
} else {
e220ttl.setMode(MODE_2_WOR_RECEIVER);
delay(delayTime);
esp_sleep_enable_ext0_wakeup(GPIO_NUM_15, 0);
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");
}
gpio_deep_sleep_hold_en();
//Serial.println("Going to sleep now");
delay(1);
//enterDeepSleep(); // Explicitly call deep sleep
}
//e220ttl.setMode(MODE_0_NORMAL);
//delay(delayTime);
Serial.println();
Serial.println("Wake and start listening!");
}
// The loop function is called in an endless loop
void loop() {
while(e220ttl.available() > 1) {
Serial.println("\nMessage arrived!");
ResponseStructContainer rsc = e220ttl.receiveMessage(sizeof(Message));
// Is something goes wrong print error
if (rsc.status.code!=1){
Serial.println(rsc.status.getResponseDescription());
}else{
// Print the data received
Serial.println(rsc.status.getResponseDescription());
struct Message message = *(Message*) rsc.data;
//Serial.println(message.type);
Serial.println(message.switchState);
Serial.println(message.timestamp);
data = message.switchState;
free(rsc.data);
rsc.close();
Serial.print("data: ");
Serial.println(data);
}
e220ttl.setMode(MODE_0_NORMAL);
delay(1000);
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());
delay(10);
Serial.println("Gets here 2");
Serial.print("data before interrupt: ");
Serial.println(data);
if (interruptExecuted) {
interruptExecuted = false;
detachInterrupt(AUX_PIN);
Serial.println("WakeUp Callback, AUX pin go LOW and start receive message!\n");
Serial.print("After Interrupt: ");
Serial.println(data);
//------------------------- Task execution ------------------------------
if (data == 1) {
digitalWrite(TRIGGER, HIGH);
delay(pulseDuration);
digitalWrite(TRIGGER, LOW);
switch_State = digitalRead(TRIGGER); // Read current switch state
Serial.println("\nBattery power switched ON");
Serial.println("ESP32 wake from Deep Sleep\n");
//getINA226(dtStamp);
char dtStamp[MAX_TIMESTAMP_LENGTH];
strncpy(dtStamp, message.timestamp, MAX_TIMESTAMP_LENGTH); // Copy timestamp
//logBattery(dtStamp); // Pass temporary copy
enterDeepSleep();
}
if (data == 2) {
digitalWrite(TRIGGER, HIGH);
delay(pulseDuration);
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");
delay(1000);
enterDeepSleep();
}
if (event) {
digitalWrite(TRIGGER, HIGH);
delay(pulseDuration);
digitalWrite(TRIGGER, LOW);
ina226.readAndClearFlags(); // reads interrupt and overflow flags and deletes them
//getINA226(dtStamp); //displayResults();
attachInterrupt(digitalPinToInterrupt(ALERT), alert, FALLING);
event = false;
digitalWrite(TRIGGER, LOW);
ina226.readAndClearFlags();
enterDeepSleep();
}
//----------------------End Task Execution ------------------------
data = 0;
}
}
}
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("Shunt 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("----------------------------------------");
}
// E220_Structure_Sender.ino
// 06/27/2024 13:22 EST
#include <Arduino.h>
#include "WiFi.h"
#include <WiFiUdp.h>
#include <HTTPClient.h>
#include <time.h>
#include "LoRa_E220.h"
#include <AsyncTCP.h>
#include "ESPAsyncWebServer.h"
#include <esp_sleep.h>
#include <Ticker.h>
#import "index7.h" // Video feed HTML; do not remove
#define DESTINATION_ADDL 3
#define FREQENCY_915
WiFiClient client;
boolean connected = false;
WiFiUDP udp;
const int udpPort = 1337;
char incomingPacket[255];
const char *udpAddress1 = "pool.ntp.org";
const char *udpAddress2 = "time.nist.gov";
#define TZ "EST+5EDT,M3.2.0/2,M11.1.0/2"
LoRa_E220 e220ttl(&Serial2, 18, 21, 19); // RX AUX M0 M1
#define AUX_PIN GPIO_NUM_18
#define RXD1 16
#define TXD1 17
int delayTime = 1000; //setMode delay
const char *ssid = "R2D2";
const char *password = "sissy4357";
AsyncWebServer server(80);
struct DateTime {
int year;
int month;
int day;
int hour;
int minute;
int second;
};
const int MAX_TIMESTAMP_LENGTH = 30;
struct Message {
int switchState;
char timestamp[MAX_TIMESTAMP_LENGTH];
};
Ticker oneTick;
Ticker onceTick;
String linkAddress = "xxx.xxx.xxx.xxx:80";
portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;
volatile int watchdogCounter = 0;
int data = 0;
int cameraPowerOff = 0;
int cameraFlag;
int needAnotherCountdown = 0;
bool got_interrupt = false;
void ISRwatchdog() {
portENTER_CRITICAL_ISR(&mux);
watchdogCounter++;
portEXIT_CRITICAL_ISR(&mux);
}
void ISRcamera() {
batteryOff();
}
void interruptHandler() {
got_interrupt = true;
}
void setup() {
Serial.begin(9600);
delay(500);
Serial1.begin(9600, SERIAL_8N1, RXD1, TXD1);
delay(500);
wifi_Start();
pinMode(AUX_PIN, INPUT);
attachInterrupt(digitalPinToInterrupt(AUX_PIN), interruptHandler, FALLING);
e220ttl.begin();
e220ttl.setMode(MODE_1_WOR_TRANSMITTER);
Serial.println("\nHi, I'm going to send WOR message!");
ResponseStatus rs = e220ttl.sendFixedMessage(0, DESTINATION_ADDL, 66, "Hello, world? WOR!");
Serial.println(rs.getResponseDescription());
Serial.println("\n\n\nWebserver and E220-900T30D Remote Switch\n");
configTime(0, 0, "pool.ntp.org", "time.nist.gov");
setenv("TZ", TZ, 1);
tzset();
server.on("/relay", HTTP_GET, [](AsyncWebServerRequest *request) {
request->send_P(200, PSTR("text/html"), HTML7, processor7);
data = 1;
needAnotherCountdown = 1;
countdownTrigger();
});
server.begin();
oneTick.attach(1.0, ISRwatchdog);
}
void loop() {
DateTime currentDateTime = getCurrentDateTime();
if ((currentDateTime.minute % 15 == 0) && (currentDateTime.second == 0)) {
// webInterface(); // Uncomment if needed
}
if (Serial.available()) {
Message message;
message.switchState = Serial.read();
String timestamp = get_time();
timestamp.toCharArray(message.timestamp, MAX_TIMESTAMP_LENGTH);
ResponseStatus rs = e220ttl.sendFixedMessage(0, DESTINATION_ADDL, 66, &message, sizeof(Message));
Serial.println(rs.getResponseDescription());
}
}
String processor7(const String &var) {
if (var == F("LINK"))
return linkAddress;
return String();
}
void batteryOff() {
int data = 2;
switchOne(data);
onceTick.detach();
}
void countdownTrigger() {
// Perform countdown actions here
Serial.println("\nCountdown timer triggered!\n");
//getDateTime();
// Schedule the next countdown if needed
if (needAnotherCountdown == 1) {
onceTick.once(60, ISRcamera);
int data = 1;
switchOne(data);
needAnotherCountdown = 0;
}
}
DateTime getCurrentDateTime() {
DateTime currentDateTime;
time_t now = time(nullptr);
struct tm *ti = localtime(&now);
currentDateTime.year = ti->tm_year + 1900;
currentDateTime.month = ti->tm_mon + 1;
currentDateTime.day = ti->tm_mday;
currentDateTime.hour = ti->tm_hour;
currentDateTime.minute = ti->tm_min;
currentDateTime.second = ti->tm_sec;
return currentDateTime;
}
String get_time() {
time_t now;
time(&now);
char time_output[MAX_TIMESTAMP_LENGTH];
strftime(time_output, MAX_TIMESTAMP_LENGTH, "%a %m/%d/%y %T", localtime(&now));
return String(time_output);
}
void switchOne(int data) {
if (data == 1) {
int data = 1;
Serial.println("\nBattery Switch is ON");
Serial.println("ESP32 waking from Deep Sleep\n");
}
if (data == 2) {
int data = 2;
Serial.println("\nBattery power switched OFF");
Serial.println("ESP32 going to Deep Sleep\n");
}
Serial.println("Hi, I'm going to send message!");
get_time();
Message message;
//initialize struct members
message.switchState = data;
// Initialize the timestamp
String timestamp = get_time();
timestamp.toCharArray(message.timestamp, MAX_TIMESTAMP_LENGTH);
Serial.print("TimeStamp: "); Serial.println(message.timestamp);
// Send message
ResponseStatus rs = e220ttl.sendFixedMessage(0, DESTINATION_ADDL, 66, &message, sizeof(Message));
// Check If there is some problem of succesfully send
Serial.println(rs.getResponseDescription());
}
void wifi_Start() {
WiFi.mode(WIFI_AP_STA);
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
IPAddress ip(10, 0, 0, 27);
IPAddress gateway(10, 0, 0, 1);
IPAddress subnet(255, 255, 255, 0);
IPAddress dns(10, 0, 0, 1);
WiFi.config(ip, gateway, subnet, dns);
while (WiFi.waitForConnectResult() != WL_CONNECTED) {
delay(1000);
}
Serial.print("Server IP: ");
Serial.println(WiFi.localIP());
Serial.print("Port: 80");
Serial.print("MAC: ");
Serial.println(WiFi.macAddress());
Serial.print("Wi-Fi Channel: ");
Serial.println(WiFi.channel());
Serial.printf("Connection result: %d\n", WiFi.waitForConnectResult());
server.begin();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment