@horace
#include "Arduino.h"
#include "LoRa_E220.h"
#include "CustomJWT.h"
#include "ArduinoJson.h"
#include <WiFi.h>
#include <HTTPClient.h>
#include <map>
#include "SD.h"
#include <NTPClient.h>
#define PIN_M0 25
#define PIN_M1 26
#define PIN_AUX 34
const int CS = 2;
const char* wifiName = "(WIFI NAME HERE)";
const char* wifiPassword = "(WIFI PASS HERE)";
const char* postUrlApi = "(API HERE)";
char key[] = "teste";
CustomJWT jwt(key, 256);
LoRa_E220 e220ttl(&Serial2, PIN_AUX, PIN_M0, PIN_M1); // RX AUX M0 M1
int farmId = 1;
const char* hashingKey = "(KEY HERE)"; // Key for hashing devID
int dBmRssi = 0;
std::map<int, int> lastPacket;
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", -3 * 3600, 60000); // UTC-3 for Brasília time
struct Interval {
int startHour;
int startMinute;
int endHour;
int endMinute;
};
Interval intervals[] = {
{7, 31, 7, 59}, // Interval from 07:31 to 07:59
{18, 31, 18, 59}, // Interval from 18:31 to 18:59
{23, 1, 23, 59} // Interval from 23:01 to 23:59
};
const int NUM_INTERVALS = sizeof(intervals) / sizeof(intervals[0]);
void setup() {
Serial.begin(9600);
delay(100);
e220ttl.begin();
setParameters();
WiFi.mode(WIFI_STA);
WiFi.disconnect();
WiFi.begin(wifiName, wifiPassword);
Serial.println(WiFi.status());
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(250);
}
Serial.println();
Serial.println("Connected!");
// SD Initialization
if (!SD.begin(CS)) {
Serial.println("SD initialization failed!");
return;
}
Serial.println("SD initialized.");
if (SD.exists("/devices")) {
Serial.println("The /devices directory exists.");
} else {
Serial.println("The /devices directory does not exist. Trying to create...");
if (SD.mkdir("/devices")) {
Serial.println("Directory /devices created successfully.");
} else {
Serial.println("Failed to create the /devices directory.");
}
}
}
void loop() {
timeClient.update();
int currentHour = timeClient.getHours();
int currentMinute = timeClient.getMinutes();
if (e220ttl.available() > 1) {
jwt.allocateJWTMemory();
ResponseContainer rc = e220ttl.receiveMessageRSSI();
String message = rc.data;
dBmRssi = -(256 - rc.rssi);
int len = message.length();
const char* pack = message.c_str();
int length = strlen(pack);
message[length] = '\0';
char* packet = unconstchar(pack);
jwt.decodeJWT(packet);
String payload = jwt.payload;
JsonDocument doc;
extractData(payload, doc);
int field_1 = doc["deviceId"];
int field_2 = doc["sectionFarm"];
int field_3 = doc["packetId"];
float field_4 = doc["voltage"];
float field_5 = doc["humidity0to10"];
float field_6 = doc["humidity10to20"];
float field_7 = doc["humidity20to30"];
float field_8 = doc["temperature"];
float field_9 = doc["fruitSize"];
float field_10 = doc["stemSize"];
String field_11 = doc["dateCreate"];
int loraDeviceId = doc["deviceId"];
if (loraDeviceId != NULL) {
if (lastPacket.find(loraDeviceId) == lastPacket.end() || field_3 != lastPacket[loraDeviceId]) {
Serial.printf("Header: %s\nHeader Length: %d\n", jwt.header, jwt.headerLength);
Serial.printf("Payload: %s\nPayload Length: %d\n", jwt.payload, jwt.payloadLength);
Serial.printf("Signature: %s\nSignature Length: %d\n", jwt.signature, jwt.signatureLength);
Serial.println("-------------------------");
Serial.print("[DEVICE ("); Serial.print(field_1); Serial.print(") - SECTION ("); Serial.print(field_2); Serial.println(")]");
Serial.print("RSSI: "); Serial.println(dBmRssi);
Serial.print("[1] Packet: "); Serial.println(field_3);
Serial.print("[2] Voltage: "); Serial.println(field_4);
Serial.print("[3] Humidity (0-10): "); Serial.println(field_5);
Serial.print("[4] Humidity (10-20): "); Serial.println(field_6);
Serial.print("[5] Humidity (20-30): "); Serial.println(field_7);
Serial.print("[6] Temperature: "); Serial.println(field_8);
Serial.print("[7] Fruit Size: "); Serial.println(field_9);
Serial.print("[8] Stem Size: "); Serial.println(field_10);
Serial.print("[9] Date-Time: "); Serial.println(field_11);
int sectionId = doc["sectionFarm"];
String devId = generateId(loraDeviceId, sectionId, farmId);
postApi(doc, devId);
lastPacket[loraDeviceId] = field_3;
jwt.clear();
}
}
}
if (connectedToInternet() && e220ttl.available() <= 1 && resendInterval(currentHour, currentMinute)) {
resendJson();
}
if (WiFi.status() != WL_CONNECTED) {
for (int i = 0; i < 3; i++) {
WiFi.begin(wifiName, wifiPassword);
if (WiFi.status() == WL_CONNECTED) {
Serial.println("Reconnected");
break;
}
Serial.println("Trying to reconnect...");
delay(2000);
}
}
}
void extractData(String message, JsonDocument& doc) {
int indexD = message.indexOf('D');
doc["deviceId"] = message.substring(0, indexD).toInt();
int indexS = message.indexOf('S');
doc["sectionFarm"] = message.substring(indexD + 1, indexS).toInt();
int indexP = message.indexOf('P');
doc["packetId"] = message.substring(indexS + 1, indexP).toInt();
int indexV = message.indexOf('V');
doc["voltage"] = message.substring(indexP + 1, indexV).toFloat();
int indexU1 = message.indexOf('U');
int indexU2 = message.indexOf('U', indexU1 + 1);
int indexU3 = message.indexOf('U', indexU2 + 1);
doc["humidity0to10"] = message.substring(indexV + 1, indexU1).toFloat();
doc["humidity10to20"] = message.substring(indexU1 + 1, indexU2).toFloat();
doc["humidity20to30"] = message.substring(indexU2 + 1, indexU3).toFloat();
int indexT = message.indexOf('T');
doc["temperature"] = message.substring(indexU3 + 1, indexT).toFloat();
int indexC = message.indexOf('C');
doc["stemSize"] = message.substring(indexT + 1, indexC).toFloat();
int indexF = message.indexOf('F');
doc["fruitSize"] = message.substring(indexC + 1, indexF).toFloat();
doc["dateCreate"] = message.substring(indexF + 1);
}
void postApi(JsonDocument doc, String devId) {
String json;
JsonDocument data;
int deviceId = doc["deviceId"];
data["deviceId"] = deviceId;
data["id"] = 0;
data["devId"] = devId;
data["humidity0to10"] = doc["humidity0to10"];
data["humidity10to20"] = doc["humidity10to20"];
data["humidity20to30"] = doc["humidity20to30"];
data["fruitSize"] = doc["fruitSize"];
data["latitude"] = "-9.363859429356404";
data["longitude"] = "-40.53890312404104";
data["dateCreate"] = doc["dateCreate"];
data["temperature"] = doc["temperature"];
data["voltage"] = doc["packetId"];
data["rssi"] = dBmRssi;
bool serialized = false;
for (int i = 0; i < 5; ++i) {
serializeJson(data, json);
if (!json.isEmpty()) {
serialized = true;
break;
}
delay(100);
}
if (!serialized) {
Serial.println("Failed to serialize JSON.");
return;
}
Serial.println(json);
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
http.begin(postUrlApi);
http.addHeader("Content-Type", "application/json");
int responseCode = http.POST(json);
if (responseCode != 200) {
saveToSD(json, deviceId, doc["dateCreate"]);
}
Serial.println(responseCode);
http.end();
} else {
saveToSD(json, deviceId, doc["dateCreate"]);
}
}
void saveToSD(String json, int deviceId, String dateCreate) {
String dirPath = "/devices/device_" + String(deviceId);
int maxAttempts = 5;
int attempts = 0;
bool dirCreated = false;
while (attempts < maxAttempts) {
if (SD.exists(dirPath)) {
Serial.println("Directory found: " + dirPath);
dirCreated = true;
break;
} else {
Serial.println("Directory not found. Trying to create: " + dirPath);
if (SD.mkdir(dirPath)) {
Serial.println("Directory created successfully: " + dirPath);
dirCreated = true;
break;
} else {
Serial.println("Failed to create directory: " + dirPath);
attempts++;
delay(100);
}
}
}
if (!dirCreated) {
Serial.println("Unable to create directory.");
return;
}
String datePart = dateCreate.substring(0, 10);
String timePart = dateCreate.substring(11, 19);
datePart.replace("-", "");
timePart.replace(":", "");
String fileName = "Json_" + datePart + "_" + timePart + ".txt";
String filePath = dirPath + "/" + fileName;
attempts = 0;
bool fileCreated = false;
while (attempts < maxAttempts) {
File file = SD.open(filePath, FILE_WRITE);
if (file) {
file.println(json);
file.close();
Serial.println("File saved: " + filePath);
fileCreated = true;
break;
} else {
Serial.println("Error opening file: " + filePath);
attempts++;
delay(100);
}
}
if (!fileCreated) {
Serial.println("Unable to create file.");
}
}
void resendJson() {
File root = SD.open("/devices");
if (!root || !root.isDirectory()) {
Serial.println("Error opening folder /devices");
return;
}
File deviceFolder = root.openNextFile();
while (deviceFolder) {
if (deviceFolder.isDirectory()) {
File jsonFile = deviceFolder.openNextFile();
while (jsonFile) {
if (!jsonFile.isDirectory()) {
String filePath = String(deviceFolder.name()) + "/" + String(jsonFile.name());
Serial.print("Sending file: ");
Serial.println(filePath);
String json;
while (jsonFile.available()) {
json += char(jsonFile.read());
}
jsonFile.close();
HTTPClient http;
http.begin(postUrlApi);
http.addHeader("Content-Type", "application/json");
int responseCode = http.POST(json);
if (responseCode == 200 || responseCode == 400) {
Serial.println("Response code " + String(responseCode) + ". Removing file.");
if (SD.remove("/devices/" + filePath)) {
Serial.println("File removed: " + filePath);
} else {
Serial.println("Failed to remove file: " + filePath);
}
} else {
Serial.println("Error sending to API. Response code: " + String(responseCode));
}
http.end();
delay(1000);
}
jsonFile = deviceFolder.openNextFile();
}
}
deviceFolder = root.openNextFile();
}
root.close();
}
bool connectedToInternet() {
WiFiClient client;
if (!client.connect("www.google.com", 80)) {
return false;
}
client.stop();
return true;
}
String generateId(int loraDeviceId, int sectionId, int farmId) {
String hash1 = generateHash(loraDeviceId);
String hash2 = generateHash(sectionId);
String hash3 = generateHash(farmId);
return hash1 + "-" + hash2 + "-" + hash3;
}
String generateHash(int id) {
String input = String(id) + hashingKey;
unsigned long hash = 0;
for (int i = 0; i < input.length(); i++) {
hash = 31 * hash + input.charAt(i);
}
String hashedId = String(hash, HEX);
while (hashedId.length() < 8) {
hashedId = "0" + hashedId;
}
return hashedId;
}
bool resendInterval(int hour, int minute) {
for (int i = 0; i < NUM_INTERVALS; ++i) {
if ((hour > intervals[i].startHour || (hour == intervals[i].startHour && minute >= intervals[i].startMinute)) &&
(hour < intervals[i].endHour || (hour == intervals[i].endHour && minute < intervals[i].endMinute))) {
return true;
}
}
return false;
}
char* unconstchar(const char* s) {
if (!s)
return NULL;
int i;
char* res = NULL;
res = (char*)malloc(strlen(s) + 1);
if (!res) {
fprintf(stderr, "Memory Allocation Failed! Exiting...\n");
exit(EXIT_FAILURE);
} else {
for (i = 0; s[i] != '\0'; i++) {
res[i] = s[i];
}
res[i] = '\0';
return res;
}
}
void setParameters() {
ResponseStructContainer c;
c = e220ttl.getConfiguration();
Configuration configuration = *(Configuration*)c.data;
configuration.ADDH = 0x00;
configuration.ADDL = 0x04;
configuration.CHAN = 0x41;
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_30;
configuration.TRANSMISSION_MODE.enableRSSI = RSSI_ENABLED;
configuration.TRANSMISSION_MODE.fixedTransmission = FT_FIXED_TRANSMISSION;
configuration.TRANSMISSION_MODE.enableLBT = LBT_DISABLED;
configuration.TRANSMISSION_MODE.WORPeriod = WOR_2000_011;
e220ttl.setConfiguration(configuration, WRITE_CFG_PWR_DWN_SAVE);
printParameters(configuration);
c.close();
}
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("----------------------------------------");
}