Compare commits
5 Commits
master
...
wifimanage
| Author | SHA1 | Date |
|---|---|---|
|
|
4441233402 | |
|
|
2b9036abcb | |
|
|
7f477f5cc8 | |
|
|
c5cbf0da8a | |
|
|
b3ec7ab03c |
|
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||||
|
// for the documentation about the extensions.json format
|
||||||
|
"recommendations": [
|
||||||
|
"platformio.platformio-ide"
|
||||||
|
],
|
||||||
|
"unwantedRecommendations": [
|
||||||
|
"ms-vscode.cpptools-extension-pack"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"mqtt":
|
||||||
|
{
|
||||||
|
"server": "192.168.1.80",
|
||||||
|
"port": 1883,
|
||||||
|
"username": "simon",
|
||||||
|
"password": "bajsa123",
|
||||||
|
"id": ""
|
||||||
|
},
|
||||||
|
"lora":
|
||||||
|
{
|
||||||
|
"frequency": 433775000,
|
||||||
|
"spreadingFactor": 12,
|
||||||
|
"signalBandwidth": 125000,
|
||||||
|
"codingRate4": 5,
|
||||||
|
"power": 20
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>ESP Wi-Fi Manager</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel="icon" href="data:,">
|
||||||
|
<link rel="stylesheet" type="text/css" href="style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="topnav">
|
||||||
|
<h1>ESP Wi-Fi Manager</h1>
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<div class="card-grid">
|
||||||
|
<div class="card">
|
||||||
|
<form action="/" method="POST">
|
||||||
|
<p>
|
||||||
|
<label for="ssid">SSID</label>
|
||||||
|
<input type="text" id ="ssid" name="ssid"><br>
|
||||||
|
<label for="pass">Password</label>
|
||||||
|
<input type="text" id ="pass" name="pass"><br>
|
||||||
|
<label for="ip">IP Address</label>
|
||||||
|
<input type="text" id ="ip" name="ip" value="192.168.1.200"><br>
|
||||||
|
<label for="gateway">Gateway Address</label>
|
||||||
|
<input type="text" id ="gateway" name="gateway" value="192.168.1.1"><br>
|
||||||
|
<input type ="submit" value ="Submit">
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -13,7 +13,12 @@ platform = espressif32
|
||||||
board = ttgo-lora32-v1
|
board = ttgo-lora32-v1
|
||||||
framework = arduino
|
framework = arduino
|
||||||
monitor_speed = 115200
|
monitor_speed = 115200
|
||||||
|
build_flags =
|
||||||
|
-D DEBUG
|
||||||
lib_deps =
|
lib_deps =
|
||||||
thingpulse/ESP8266 and ESP32 OLED driver for SSD1306 displays@^4.5.0
|
https://github.com/tzapu/WiFiManager.git
|
||||||
|
bblanchon/ArduinoJson@^7.0.4
|
||||||
|
peterus/esp-logger@^1.0.0
|
||||||
|
knolleary/PubSubClient@^2.8
|
||||||
sandeepmistry/LoRa@^0.8.0
|
sandeepmistry/LoRa@^0.8.0
|
||||||
knolleary/PubSubClient@^2.8
|
thingpulse/ESP8266 and ESP32 OLED driver for SSD1306 displays@^4.5.0
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,149 @@
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
#include <SPIFFS.h>
|
||||||
|
#include "config.hpp"
|
||||||
|
#include "logger.h"
|
||||||
|
|
||||||
|
extern logging::Logger logger;
|
||||||
|
|
||||||
|
Config::Config()
|
||||||
|
{
|
||||||
|
_filePath = "/config.json";
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "CONFIG", "Init config");
|
||||||
|
if (!SPIFFS.begin(false))
|
||||||
|
{
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, "CONFIG", "SPIFFS Mount Failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
readFile(SPIFFS, _filePath.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::readFile(fs::FS &fs, const char *fileName)
|
||||||
|
{
|
||||||
|
JsonDocument data;
|
||||||
|
File configFile = fs.open(fileName, "r");
|
||||||
|
DeserializationError error = deserializeJson(data, configFile);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, "CONFIG", "Failed to read file, using default configuration");
|
||||||
|
}
|
||||||
|
|
||||||
|
MqttConfig mqtt;
|
||||||
|
mqtt.server = data["mqtt"]["server"].as<String>();
|
||||||
|
mqtt.port = data["mqtt"]["port"].as<int>();
|
||||||
|
mqtt.username = data["mqtt"]["username"].as<String>();
|
||||||
|
mqtt.password = data["mqtt"]["password"].as<String>();
|
||||||
|
mqtt.id = data["mqtt"]["id"].as<String>();
|
||||||
|
|
||||||
|
LoraConfig lora;
|
||||||
|
lora.frequency = data["lora"]["frequency"].as<long>();
|
||||||
|
lora.spreadingFactor = data["lora"]["spreadingFactor"].as<int>();
|
||||||
|
lora.signalBandwidth = data["lora"]["signalBandwidth"].as<long>();
|
||||||
|
lora.codingRate4 = data["lora"]["codingRate4"].as<int>();
|
||||||
|
lora.power = data["lora"]["power"].as<int>();
|
||||||
|
logConfigInfo(data);
|
||||||
|
configFile.close();
|
||||||
|
|
||||||
|
mqttConfig = mqtt;
|
||||||
|
loraConfig = lora;
|
||||||
|
|
||||||
|
isConfigLoaded = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::writeData()
|
||||||
|
{
|
||||||
|
JsonDocument doc;
|
||||||
|
|
||||||
|
JsonObject mqttJson = doc["mqtt"].to<JsonObject>();
|
||||||
|
mqttJson["server"] = this->mqttConfig.server;
|
||||||
|
mqttJson["port"] = this->mqttConfig.port;
|
||||||
|
mqttJson["username"] = this->mqttConfig.username;
|
||||||
|
mqttJson["password"] = this->mqttConfig.password;
|
||||||
|
mqttJson["id"] = this->mqttConfig.id;
|
||||||
|
mqttJson["topic"] = this->mqttConfig.topic;
|
||||||
|
|
||||||
|
JsonObject lora = doc["lora"].to<JsonObject>();
|
||||||
|
lora["frequency"] = 433775000;
|
||||||
|
lora["spreadingFactor"] = 12;
|
||||||
|
lora["signalBandwidth"] = 125000;
|
||||||
|
lora["codingRate4"] = 5;
|
||||||
|
lora["power"] = 20;
|
||||||
|
|
||||||
|
// Delete existing file, otherwise the configuration is appended to the file
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "CONFIG", "Write DATA to file");
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "CONFIG", ("Server: " + String(this->mqttConfig.server)).c_str());
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "CONFIG", ("Port: " + String(this->mqttConfig.port)).c_str());
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "CONFIG", ("Username: " + String(this->mqttConfig.username)).c_str());
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "CONFIG", ("Password: " + String(this->mqttConfig.password)).c_str());
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "CONFIG", ("ID: " + String(this->mqttConfig.id)).c_str());
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "CONFIG", ("Topic: " + String(this->mqttConfig.topic)).c_str());
|
||||||
|
|
||||||
|
|
||||||
|
SPIFFS.remove(_filePath);
|
||||||
|
File configFile = SPIFFS.open(_filePath.c_str(), "w");
|
||||||
|
if (!configFile)
|
||||||
|
{
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, "CONFIG", "Failed to open file for writing");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serialize the JSON document to the file
|
||||||
|
if (serializeJson(doc, configFile) == 0)
|
||||||
|
{
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, "CONFIG", "Failed to write to file");
|
||||||
|
}
|
||||||
|
|
||||||
|
logConfigInfo(doc);
|
||||||
|
// Close the file
|
||||||
|
configFile.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::logConfigInfo(JsonDocument& doc) {
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "CONFIG", "Logging configuration data:");
|
||||||
|
|
||||||
|
JsonObject rootJson = doc.as<JsonObject>();
|
||||||
|
|
||||||
|
// Iterate over each key-value pair at the root level
|
||||||
|
for (auto kvp : rootJson) {
|
||||||
|
String key = kvp.key().c_str();
|
||||||
|
String value;
|
||||||
|
|
||||||
|
// Get the value associated with the key
|
||||||
|
const JsonVariant& jsonValue = kvp.value();
|
||||||
|
|
||||||
|
// Check the type of the JSON value and convert it to a string accordingly
|
||||||
|
if (jsonValue.is<String>()) {
|
||||||
|
value = jsonValue.as<String>();
|
||||||
|
} else if (jsonValue.is<int>()) {
|
||||||
|
value = String(jsonValue.as<int>());
|
||||||
|
} else if (jsonValue.is<long>()) {
|
||||||
|
value = String(jsonValue.as<long>());
|
||||||
|
} else if (jsonValue.is<bool>()) {
|
||||||
|
value = jsonValue.as<bool>() ? "true" : "false";
|
||||||
|
} else if (jsonValue.is<JsonArray>() || jsonValue.is<JsonObject>()) {
|
||||||
|
JsonDocument tempJson;
|
||||||
|
tempJson.set(jsonValue);
|
||||||
|
serializeJson(tempJson, value);
|
||||||
|
} else if (jsonValue.isNull()) {
|
||||||
|
value = "null";
|
||||||
|
} else {
|
||||||
|
value = "Unsupported data type";
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "CONFIG", (key + ": " + value).c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MqttConfig::setMqtt(const String &server, const int &port, const String &username, const String &password, const String &topic)
|
||||||
|
{
|
||||||
|
this->server = server;
|
||||||
|
this->port = port;
|
||||||
|
this->username = username;
|
||||||
|
this->password = password;
|
||||||
|
this->topic = topic;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MqttConfig::setId(const String &id)
|
||||||
|
{
|
||||||
|
this->id = id;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
#ifndef CONFIG_H
|
||||||
|
#define CONFIG_H
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <FS.h>
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
|
||||||
|
class MqttConfig {
|
||||||
|
public:
|
||||||
|
String server;
|
||||||
|
int port;
|
||||||
|
String username;
|
||||||
|
String password;
|
||||||
|
String id;
|
||||||
|
String topic;
|
||||||
|
void setId(const String& id);
|
||||||
|
void setMqtt(const String& server, const int& port, const String& username, const String& password, const String& topic);
|
||||||
|
};
|
||||||
|
|
||||||
|
class LoraConfig {
|
||||||
|
public:
|
||||||
|
long frequency;
|
||||||
|
int spreadingFactor;
|
||||||
|
long signalBandwidth;
|
||||||
|
int codingRate4;
|
||||||
|
int power;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Config {
|
||||||
|
public:
|
||||||
|
bool isConfigLoaded = false;
|
||||||
|
MqttConfig mqttConfig;
|
||||||
|
LoraConfig loraConfig;
|
||||||
|
Config();
|
||||||
|
void writeData();
|
||||||
|
void setMqttConfig(const String& server, const int& port, const String& username, const String& password, const String& topic) {
|
||||||
|
mqttConfig.setMqtt(server, port, username, password, topic);
|
||||||
|
}
|
||||||
|
void setMqttId(const String& id){
|
||||||
|
mqttConfig.setId(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void logConfigInfo(JsonDocument& configJson);
|
||||||
|
private:
|
||||||
|
void readFile(fs::FS &fs, const char *fileName);
|
||||||
|
String _filePath;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* CONFIG_H */
|
||||||
|
|
@ -0,0 +1,125 @@
|
||||||
|
#include "display.hpp"
|
||||||
|
#include "config.hpp"
|
||||||
|
#include "logger.h"
|
||||||
|
|
||||||
|
extern logging::Logger logger;
|
||||||
|
|
||||||
|
// Constructor to initialize the display with I2C parameters
|
||||||
|
Display::Display()
|
||||||
|
: display(DISPLAY_ADDRESS, DISPLAY_SDA, DISPLAY_SCL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Display::setup_display()
|
||||||
|
{
|
||||||
|
pinMode(16, OUTPUT);
|
||||||
|
digitalWrite(16, LOW); // set GPIO16 low to reset OLED
|
||||||
|
delay(50);
|
||||||
|
digitalWrite(16, HIGH);
|
||||||
|
if (!display.init())
|
||||||
|
{
|
||||||
|
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, "DISPLAY", "Display initialization failed!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
display.flipScreenVertically();
|
||||||
|
display.setFont(ArialMT_Plain_10);
|
||||||
|
display.setTextAlignment(TEXT_ALIGN_LEFT);
|
||||||
|
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "DISPLAY", "Display init done!");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Display::display_toggle(bool toggle)
|
||||||
|
{
|
||||||
|
displayOn = toggle;
|
||||||
|
if (displayOn)
|
||||||
|
{
|
||||||
|
display.displayOn();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
display.displayOff();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Display::cleanTFT()
|
||||||
|
{
|
||||||
|
display.clear();
|
||||||
|
display.display();
|
||||||
|
display.setFont(ArialMT_Plain_10);
|
||||||
|
}
|
||||||
|
void Display::show_display(String header, int wait)
|
||||||
|
{
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "DISPLAY", "One line: %s", header.c_str());
|
||||||
|
cleanTFT();
|
||||||
|
display.setFont(ArialMT_Plain_24);
|
||||||
|
display.drawString(0, 20, header);
|
||||||
|
display.display();
|
||||||
|
delay(wait);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Display::show_display(String header, String line1, int wait)
|
||||||
|
{
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "DISPLAY", "Two lines: \n %s, \n %s", header.c_str(), line1.c_str());
|
||||||
|
cleanTFT();
|
||||||
|
display.setFont(ArialMT_Plain_16);
|
||||||
|
display.drawString(0, 0, header);
|
||||||
|
display.drawString(0, 18, line1);
|
||||||
|
display.display();
|
||||||
|
delay(wait);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Display::show_display(String header, String line1, String line2, int wait)
|
||||||
|
{
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "DISPLAY", "Three lines: %s, %s, %s", header.c_str(), line1.c_str(), line2.c_str());
|
||||||
|
cleanTFT();
|
||||||
|
display.drawString(0, 0, header);
|
||||||
|
display.drawString(0, 12, line1);
|
||||||
|
display.drawString(0, 24, line2);
|
||||||
|
display.display();
|
||||||
|
delay(wait);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Display::show_display(String header, String line1, String line2, String line3, int wait)
|
||||||
|
{
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "DISPLAY", "Four lines: %s, %s, %s, %s", header.c_str(), line1.c_str(), line2.c_str(), line3.c_str());
|
||||||
|
cleanTFT();
|
||||||
|
display.drawString(0, 0, header);
|
||||||
|
display.drawString(0, 12, line1);
|
||||||
|
display.drawString(0, 24, line2);
|
||||||
|
display.drawString(0, 36, line3);
|
||||||
|
display.display();
|
||||||
|
delay(wait);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Display::show_display(String header, String line1, String line2, String line3, String line4, int wait)
|
||||||
|
{
|
||||||
|
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "DISPLAY", "Five lines: %s, %s, %s, %s, %s", header.c_str(), line1.c_str(), line2.c_str(), line3.c_str(), line4.c_str());
|
||||||
|
cleanTFT();
|
||||||
|
display.drawString(0, 0, header);
|
||||||
|
display.drawString(0, 12, line1);
|
||||||
|
display.drawString(0, 24, line2);
|
||||||
|
display.drawString(0, 36, line3);
|
||||||
|
display.drawString(0, 48, line4);
|
||||||
|
display.display();
|
||||||
|
delay(wait);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Display::show_message(const char *message, int line, int wait)
|
||||||
|
{
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "DISPLAY", "Line %d: %s", line, message);
|
||||||
|
|
||||||
|
display.setFont(ArialMT_Plain_10);
|
||||||
|
|
||||||
|
// Set cursor position based on line number (optional)
|
||||||
|
if (line >= 0 || line <= 5)
|
||||||
|
{
|
||||||
|
display.drawString(0, line * 13, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display the updated content
|
||||||
|
display.display();
|
||||||
|
|
||||||
|
delay(wait); // Convert wait time to milliseconds
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
#ifndef DISPLAY_H
|
||||||
|
#define DISPLAY_H
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
//#include <SSD1306.h>
|
||||||
|
#include "SSD1306Wire.h"
|
||||||
|
#define DISPLAY_ADDRESS 0x3c // CS --> NSS
|
||||||
|
#define DISPLAY_SDA 4
|
||||||
|
#define DISPLAY_SCL 15 // IRQ --> DIO0
|
||||||
|
|
||||||
|
|
||||||
|
class Display {
|
||||||
|
public:
|
||||||
|
Display();
|
||||||
|
|
||||||
|
void setup_display();
|
||||||
|
void display_toggle(bool toggle);
|
||||||
|
void cleanTFT();
|
||||||
|
|
||||||
|
void show_display(String header, int wait = 0);
|
||||||
|
void show_display(String header, String line1, int wait = 0);
|
||||||
|
void show_display(String header, String line1, String line2, int wait = 0);
|
||||||
|
void show_display(String header, String line1, String line2, String line3, int wait = 0);
|
||||||
|
void show_display(String header, String line1, String line2, String line3, String line4, int wait = 0);
|
||||||
|
void show_message(const char* message, int line = 0, int wait = 0);
|
||||||
|
|
||||||
|
private:
|
||||||
|
SSD1306Wire display;
|
||||||
|
bool displayOn;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* DISPLAY_H */
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
#include "config.hpp"
|
||||||
|
#include "lorahandler.hpp"
|
||||||
|
#include "logger.h"
|
||||||
|
|
||||||
|
extern logging::Logger logger;
|
||||||
|
extern Config config;
|
||||||
|
|
||||||
|
void LoraHandler::setup()
|
||||||
|
{
|
||||||
|
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "LoRa", "Set SPI pins!");
|
||||||
|
SPI.begin(LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS);
|
||||||
|
LoRa.setPins(LORA_CS, LORA_RST, LORA_IRQ);
|
||||||
|
|
||||||
|
long freq = config.loraConfig.frequency;
|
||||||
|
if (!LoRa.begin(freq))
|
||||||
|
{
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, "LoRa", "Starting LoRa failed!");
|
||||||
|
// show_display("ERROR", "Starting LoRa failed!");
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LoRa.setSpreadingFactor(config.loraConfig.spreadingFactor);
|
||||||
|
LoRa.setSignalBandwidth(config.loraConfig.signalBandwidth);
|
||||||
|
LoRa.setCodingRate4(config.loraConfig.codingRate4);
|
||||||
|
LoRa.enableCrc();
|
||||||
|
LoRa.setTxPower(config.loraConfig.power);
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "LoRa", "LoRa init done!");
|
||||||
|
String currentLoRainfo = "LoRa Freq: " + String(config.loraConfig.frequency) + " / SF:" + String(config.loraConfig.spreadingFactor) + " / CR: " + String(config.loraConfig.codingRate4);
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "LoRa", currentLoRainfo.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
ReceivedLoRaPacket LoraHandler::receivePacket()
|
||||||
|
{
|
||||||
|
ReceivedLoRaPacket receivedLoraPacket;
|
||||||
|
String packet = "";
|
||||||
|
int packetSize = LoRa.parsePacket();
|
||||||
|
if (packetSize)
|
||||||
|
{
|
||||||
|
while (LoRa.available())
|
||||||
|
{
|
||||||
|
int inChar = LoRa.read();
|
||||||
|
packet += (char)inChar;
|
||||||
|
}
|
||||||
|
receivedLoraPacket.text = packet;
|
||||||
|
receivedLoraPacket.rssi = LoRa.packetRssi();
|
||||||
|
receivedLoraPacket.snr = LoRa.packetSnr();
|
||||||
|
receivedLoraPacket.freqError = LoRa.packetFrequencyError();
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "LoRa Rx", "---> %s", packet.c_str());
|
||||||
|
}
|
||||||
|
return receivedLoraPacket;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
#ifndef LORAHANDLER_H
|
||||||
|
#define LORAHANDLER_H
|
||||||
|
|
||||||
|
#include "config.hpp"
|
||||||
|
#include <SPI.h>
|
||||||
|
#include <LoRa.h>
|
||||||
|
|
||||||
|
#define LORA_SCK 5
|
||||||
|
#define LORA_MISO 19
|
||||||
|
#define LORA_MOSI 27
|
||||||
|
#define LORA_CS 18 // CS --> NSS
|
||||||
|
#define LORA_RST 14
|
||||||
|
#define LORA_IRQ 26 // IRQ --> DIO0
|
||||||
|
|
||||||
|
struct ReceivedLoRaPacket {
|
||||||
|
String text;
|
||||||
|
int rssi;
|
||||||
|
float snr;
|
||||||
|
int freqError;
|
||||||
|
};
|
||||||
|
|
||||||
|
class LoraHandler {
|
||||||
|
public:
|
||||||
|
void setup();
|
||||||
|
ReceivedLoRaPacket receivePacket();
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* LORAHANDLER_H */
|
||||||
|
|
@ -1,200 +1,125 @@
|
||||||
// OLED
|
|
||||||
#include <Wire.h> // Only needed for Arduino 1.6.5 and earlier
|
|
||||||
#include "SSD1306.h" // alias for `#include "SSD1306Wire.h"`
|
|
||||||
|
|
||||||
// LORA
|
#include <logger.h>
|
||||||
#include <SPI.h>
|
#include "wifi.hpp"
|
||||||
#include <LoRa.h>
|
#include "mqtt.hpp"
|
||||||
|
#include "config.hpp"
|
||||||
// MQTT
|
#include "lorahandler.hpp"
|
||||||
|
#include "display.hpp"
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <PubSubClient.h>
|
|
||||||
|
|
||||||
|
Config config;
|
||||||
SSD1306 display(0x3c, 4, 15);
|
WiFiServer server(80);
|
||||||
|
|
||||||
//OLED pins to ESP32 GPIOs via this connection:
|
|
||||||
//OLED_SDA GPIO4
|
|
||||||
//OLED_SCL GPIO15
|
|
||||||
//OLED_RST GPIO16
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// WIFI_LoRa_32 ports
|
|
||||||
|
|
||||||
// GPIO5 SX1278 SCK
|
|
||||||
// GPIO19 SX1278 MISO
|
|
||||||
// GPIO27 SX1278 MOSI
|
|
||||||
// GPIO18 SX1278 CS
|
|
||||||
// GPIO14 SX1278 RESET
|
|
||||||
// GPIO26 SX1278 IRQ(Interrupt Request)
|
|
||||||
|
|
||||||
#define SS 18
|
|
||||||
#define RST 14
|
|
||||||
#define DI0 26
|
|
||||||
// #define BAND 429E6
|
|
||||||
|
|
||||||
// LoRa Settings
|
|
||||||
#define BAND 434500000.00
|
|
||||||
#define spreadingFactor 9
|
|
||||||
// #define SignalBandwidth 62.5E3
|
|
||||||
#define SignalBandwidth 31.25E3
|
|
||||||
|
|
||||||
#define codingRateDenominator 8
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// WiFi Network Credentials
|
|
||||||
const char *ssid = "SoS IOT";
|
|
||||||
const char *password = "godisr8n";
|
|
||||||
|
|
||||||
// MQTTCredentials
|
|
||||||
const char *MQTT_USER = "simon";
|
|
||||||
const char *MQTT_PASS = "bajsa123";
|
|
||||||
|
|
||||||
IPAddress broker(10,0,0,3); // IP address of your MQTT broker eg. 192.168.1.50
|
|
||||||
const char *ID = "esp_1"; // Name of our device, must be unique
|
|
||||||
const char *TOPIC = "test/sensor"; // Topic to subcribe to
|
|
||||||
WiFiClient wclient;
|
WiFiClient wclient;
|
||||||
|
Mqtt mqtt(wclient);
|
||||||
|
LoraHandler lora;
|
||||||
|
Display display;
|
||||||
|
logging::Logger logger;
|
||||||
|
|
||||||
PubSubClient client(wclient); // Setup MQTT client
|
#define TRIGGER_PIN 0
|
||||||
|
void checkButton();
|
||||||
|
|
||||||
String data = "";
|
bool portalRunning = false;
|
||||||
|
|
||||||
// Connect to WiFi network
|
void setup()
|
||||||
void setup_wifi() {
|
{
|
||||||
Serial.print("\nConnecting to ");
|
|
||||||
Serial.println(ssid);
|
|
||||||
|
|
||||||
WiFi.begin(ssid, password); // Connect to network
|
|
||||||
|
|
||||||
while (WiFi.status() != WL_CONNECTED) { // Wait for connection
|
|
||||||
delay(500);
|
|
||||||
Serial.print(".");
|
|
||||||
}
|
|
||||||
|
|
||||||
Serial.println();
|
|
||||||
Serial.println("WiFi connected");
|
|
||||||
Serial.print("IP address: ");
|
|
||||||
Serial.println(WiFi.localIP());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reconnect to client
|
|
||||||
void reconnect() {
|
|
||||||
// Loop until we're reconnected
|
|
||||||
while (!client.connected()) {
|
|
||||||
Serial.print("Attempting MQTT connection...");
|
|
||||||
// Attempt to connect
|
|
||||||
if (client.connect(ID,MQTT_USER,MQTT_PASS)) {
|
|
||||||
Serial.println("connected");
|
|
||||||
Serial.print("Publishing to: ");
|
|
||||||
Serial.println(TOPIC);
|
|
||||||
Serial.println('\n');
|
|
||||||
|
|
||||||
} else {
|
|
||||||
Serial.println(" try again in 5 seconds");
|
|
||||||
// Wait 5 seconds before retrying
|
|
||||||
delay(5000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ADC? Battery voltage
|
|
||||||
// const uint8_t vbatPin = 34;
|
|
||||||
// float VBAT; // battery voltage from ESP32 ADC read
|
|
||||||
|
|
||||||
void setup() {
|
|
||||||
pinMode(16,OUTPUT);
|
|
||||||
digitalWrite(16, LOW); // set GPIO16 low to reset OLED
|
|
||||||
delay(50);
|
|
||||||
digitalWrite(16, HIGH);
|
|
||||||
|
|
||||||
display.init();
|
|
||||||
display.flipScreenVertically();
|
|
||||||
display.setFont(ArialMT_Plain_10);
|
|
||||||
display.setTextAlignment(TEXT_ALIGN_LEFT);
|
|
||||||
|
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
while (!Serial); //if just the the basic function, must connect to a computer
|
|
||||||
delay(1000);
|
|
||||||
|
|
||||||
Serial.println("LoRa Receiver");
|
|
||||||
display.drawString(5,5,"LoRa Receiver");
|
|
||||||
display.display();
|
|
||||||
SPI.begin(5,19,27,18);
|
|
||||||
LoRa.setPins(SS,RST,DI0);
|
|
||||||
|
|
||||||
/*
|
#ifndef DEBUG
|
||||||
pinMode(vbatPin, INPUT);
|
logger.setDebugLevel(logging::LoggerLevel::LOGGER_LEVEL_INFO);
|
||||||
VBAT = (120.0/20.0) * (float)(analogRead(vbatPin)) / 1024.0; // LiPo battery voltage in volts
|
#endif
|
||||||
Serial.println("Vbat = "); Serial.print(VBAT); Serial.println(" Volts");
|
pinMode(TRIGGER_PIN, INPUT);
|
||||||
*/
|
|
||||||
|
|
||||||
if (!LoRa.begin(BAND)) {
|
WiFi.mode(WIFI_STA);
|
||||||
display.drawString(5,25,"Starting LoRa failed!");
|
config = Config();
|
||||||
while (1);
|
|
||||||
}
|
|
||||||
Serial.println("LoRa Initial OK!");
|
|
||||||
|
|
||||||
Serial.print("LoRa Frequency: ");
|
|
||||||
Serial.println(BAND);
|
|
||||||
|
|
||||||
Serial.print("LoRa Spreading Factor: ");
|
|
||||||
Serial.println(spreadingFactor);
|
|
||||||
LoRa.setSpreadingFactor(spreadingFactor);
|
|
||||||
|
|
||||||
Serial.print("LoRa Signal Bandwidth: ");
|
|
||||||
Serial.println(SignalBandwidth);
|
|
||||||
LoRa.setSignalBandwidth(SignalBandwidth);
|
|
||||||
|
|
||||||
LoRa.setCodingRate4(codingRateDenominator);
|
while (!config.isConfigLoaded)
|
||||||
|
|
||||||
display.drawString(5,25,"LoRa Initializing OK!");
|
|
||||||
display.display();
|
|
||||||
|
|
||||||
setup_wifi(); // Connect to network
|
|
||||||
client.setServer(broker, 1883);
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
if (!client.connected()) // Reconnect if connection is lost
|
|
||||||
{
|
{
|
||||||
reconnect();
|
delay(10);
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, "MAIN", "COnfig not loaded yet...");
|
||||||
}
|
}
|
||||||
client.loop();
|
delay(100);
|
||||||
// try to parse packet
|
display.setup_display();
|
||||||
int packetSize = LoRa.parsePacket();
|
display.show_display("STARTUP");
|
||||||
if (packetSize) {
|
setupWifi("island_temp", false);
|
||||||
// received a packets
|
|
||||||
Serial.print("Received packet. ");
|
mqtt.mqttSetup();
|
||||||
|
lora.setup();
|
||||||
display.clear();
|
delay(5*1000); // Show text in 5s
|
||||||
display.setFont(ArialMT_Plain_16);
|
display.cleanTFT();
|
||||||
display.drawString(3, 0, "Received packet ");
|
}
|
||||||
display.display();
|
|
||||||
|
void loop()
|
||||||
// read packet
|
{
|
||||||
while (LoRa.available()) {
|
ReceivedLoRaPacket packet = lora.receivePacket();
|
||||||
data = LoRa.readString();
|
if (packet.text.isEmpty())
|
||||||
Serial.print(data);
|
{
|
||||||
display.drawString(20,22, data);
|
packet.rssi = 69;
|
||||||
display.display();
|
packet.snr = 3.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WiFi.status() == WL_CONNECTED) { // Check WiFi connection
|
||||||
|
IPAddress ip = WiFi.localIP();
|
||||||
|
String line0 = "IP: " + ip.toString();
|
||||||
|
display.show_message(line0.c_str(), 0);
|
||||||
|
} else {
|
||||||
|
// Optional: Display message indicating WiFi not connected
|
||||||
|
display.show_message("WiFi not connected", 0);
|
||||||
|
}
|
||||||
|
int mqtt_pkt = 123455;
|
||||||
|
String line1 = "Mqtt pkt: " + String(mqtt_pkt);
|
||||||
|
display.show_message(line1.c_str(), 1);
|
||||||
|
|
||||||
|
String line2 = "Last lora, rssi: " + String(packet.rssi ) ;
|
||||||
|
display.show_message(line2.c_str(), 2);
|
||||||
|
display.show_message("Fourth", 3);
|
||||||
|
display.show_message("Fifth", 4);
|
||||||
|
sleep(5);
|
||||||
|
/*
|
||||||
|
mqtt.mqttRun();
|
||||||
|
if (portalRunning)
|
||||||
|
{
|
||||||
|
wm.process();
|
||||||
|
}
|
||||||
|
mqtt.mqttPublish("test/sensor", "123");
|
||||||
|
checkButton();
|
||||||
|
sleep(10);*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkButton()
|
||||||
|
{
|
||||||
|
// check for button press
|
||||||
|
if (digitalRead(TRIGGER_PIN) == LOW)
|
||||||
|
{
|
||||||
|
// poor mans debounce/press-hold, code not ideal for production
|
||||||
|
delay(50);
|
||||||
|
if (digitalRead(TRIGGER_PIN) == LOW)
|
||||||
|
{
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "Main", "Button Pressed once, wait 3s");
|
||||||
|
// still holding button for 3000 ms
|
||||||
|
delay(3000); // reset delay hold
|
||||||
|
if (digitalRead(TRIGGER_PIN) == LOW)
|
||||||
|
{
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "Main", "Button Pressed, Starting Portal");
|
||||||
|
wm.startWebPortal();
|
||||||
|
portalRunning = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// start portal w delay
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "Main", "Starting config portal");
|
||||||
|
Serial.println("Starting config portal");
|
||||||
|
wm.setConfigPortalTimeout(120);
|
||||||
|
|
||||||
|
if (!wm.startConfigPortal("island_temp"))
|
||||||
|
{
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "Main", "failed to connect or hit timeout");
|
||||||
|
delay(3000);
|
||||||
|
// ESP.restart();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// if you get here you have connected to the WiFi
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "Main", "connected...yeey :)");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// print RSSI of packet
|
|
||||||
Serial.print(" with RSSI ");
|
|
||||||
Serial.println(LoRa.packetRssi());
|
|
||||||
Serial.print(" with SNR ");
|
|
||||||
Serial.println(LoRa.packetSnr());
|
|
||||||
// display.drawString(0, 45, "RSSI: ");
|
|
||||||
// display.drawString(50, 45, (String)LoRa.packetRssi());
|
|
||||||
|
|
||||||
display.drawString(0, 45, (String)LoRa.packetRssi() + "dB (" + (String)LoRa.packetSnr() +"dB)");
|
|
||||||
|
|
||||||
display.display();
|
|
||||||
client.publish(TOPIC, data.c_str() );
|
|
||||||
Serial.println((String)TOPIC + " => " + data + ";");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,123 @@
|
||||||
|
#include "mqtt.hpp"
|
||||||
|
#include "config.hpp"
|
||||||
|
#include <PubSubClient.h>
|
||||||
|
#include "logger.h"
|
||||||
|
|
||||||
|
extern logging::Logger logger;
|
||||||
|
|
||||||
|
extern Config config;
|
||||||
|
extern Config config;
|
||||||
|
|
||||||
|
Mqtt::Mqtt(WiFiClient& wifiClient) : mqttClient(wifiClient) {}
|
||||||
|
|
||||||
|
void Mqtt::mqttSetup()
|
||||||
|
{
|
||||||
|
String message = "MqttServer: " + config.mqttConfig.server + ", MqttPort: " + config.mqttConfig.port;
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "MQTT", message.c_str());
|
||||||
|
if (config.mqttConfig.server.length() > 0)
|
||||||
|
{
|
||||||
|
// strcpy(mqttHost, config.mqtt.server.c_str());
|
||||||
|
String message = "MqttServer: " + config.mqttConfig.server + ", MqttPort: " + config.mqttConfig.port;
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "MQTT", message.c_str());
|
||||||
|
IPAddress mqttServerIP;
|
||||||
|
if(mqttServerIP.fromString(config.mqttConfig.server)){
|
||||||
|
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "MQTT", mqttServerIP.toString().c_str());
|
||||||
|
mqttClient.setServer(mqttServerIP, config.mqttConfig.port);
|
||||||
|
}else{
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, "MQTT", "MQTT Invalid IP address format %s", config.mqttConfig.server);
|
||||||
|
}
|
||||||
|
mqttClient.setCallback(callback);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, "MQTT", "MQTT config is not set");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mqtt::mqttRun()
|
||||||
|
{
|
||||||
|
delay(100);
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "MQTT", "MQTT RUN");
|
||||||
|
if (WiFi.status() == WL_CONNECTED && !mqttClient.loop()) {
|
||||||
|
mqttReconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mqtt::mqttReconnect()
|
||||||
|
{
|
||||||
|
int retryCount = 0;
|
||||||
|
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "MQTT", "Attempting MQTT connection...");
|
||||||
|
// Loop until we're reconnected
|
||||||
|
|
||||||
|
while (!mqttClient.connected() && retryCount < 10)
|
||||||
|
{
|
||||||
|
// Attempt to connect
|
||||||
|
String mqttId = config.mqttConfig.id;
|
||||||
|
if (mqttId.isEmpty())
|
||||||
|
{
|
||||||
|
mqttId = "ESP32-";
|
||||||
|
mqttId += String(random(0xffff), HEX);
|
||||||
|
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "MQTT", "Set ID: %s", mqttId );
|
||||||
|
config.setMqttId(mqttId);
|
||||||
|
config.writeData();
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "MQTT CONFIG", "Server: %s", config.mqttConfig.server.c_str());
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "MQTT CONFIG", "Port: %d", config.mqttConfig.port);
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "MQTT CONFIG", "Username: %s", config.mqttConfig.username.c_str());
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "MQTT CONFIG", "Password: %s", config.mqttConfig.password.c_str());
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "MQTT CONFIG", "ID: %s", config.mqttConfig.id.c_str());
|
||||||
|
|
||||||
|
if (mqttClient.connect(mqttId.c_str(), "simon", "bajsa123"))
|
||||||
|
{
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "MQTT", "connected");
|
||||||
|
String topic = config.mqttConfig.topic;
|
||||||
|
if (topic.isEmpty())
|
||||||
|
{
|
||||||
|
topic = config.mqttConfig.id;
|
||||||
|
}
|
||||||
|
mqttClient.subscribe(topic.c_str());
|
||||||
|
String message = "Subscribe to: " + topic;
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "MQTT", message.c_str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_WARN, "MQTT", "Not connected to mqtt, try again in 5 s.");
|
||||||
|
// Wait 5 seconds before retrying
|
||||||
|
delay(5000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Check if we're connected after the loop
|
||||||
|
if (!mqttClient.connected()) {
|
||||||
|
// Connection failed after maximum retries
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, "MQTT", "Failed to connect to MQTT broker after 10 retries");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mqtt::callback(char *topic, uint8_t *payload, unsigned int length)
|
||||||
|
// Not implemented yet. Just for debug
|
||||||
|
{
|
||||||
|
// Create spot in memory for message
|
||||||
|
char message[length + 1];
|
||||||
|
// Write payload to String
|
||||||
|
strncpy(message, (char *)payload, length);
|
||||||
|
// Nullify last character to eliminate garbage at end
|
||||||
|
message[length] = '\0';
|
||||||
|
|
||||||
|
// Create correct object
|
||||||
|
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "MQTT", "Received: %s", message);
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "MQTT", "From: %s", topic);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mqtt::mqttPublish(const char* topic, const char* payload){
|
||||||
|
if (mqttClient.connected()) {
|
||||||
|
mqttClient.publish(topic, payload);
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "MQTT", "Published message to %s: %s", topic, payload);
|
||||||
|
} else {
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, "MQTT", "Failed to publish message. MQTT client not connected.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef MQTT_H
|
||||||
|
#define MQTT_H
|
||||||
|
|
||||||
|
#include "wifi.hpp"
|
||||||
|
#include "config.hpp"
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <PubSubClient.h>
|
||||||
|
|
||||||
|
|
||||||
|
class Mqtt {
|
||||||
|
public:
|
||||||
|
Mqtt(WiFiClient& wifiClient);
|
||||||
|
void mqttSetup();
|
||||||
|
void mqttRun();
|
||||||
|
void mqttPublish(const char* topic, const char* payload);
|
||||||
|
private:
|
||||||
|
void mqttReconnect();
|
||||||
|
static void callback(char *topic, uint8_t *payload, unsigned int length);
|
||||||
|
PubSubClient mqttClient;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* MQTT_H */
|
||||||
|
|
@ -0,0 +1,148 @@
|
||||||
|
#include "wifi.hpp"
|
||||||
|
#include <logger.h>
|
||||||
|
|
||||||
|
WiFiManager wm;
|
||||||
|
extern Config config;
|
||||||
|
extern logging::Logger logger;
|
||||||
|
// Flag for saving data
|
||||||
|
bool shouldSaveConfig = false;
|
||||||
|
|
||||||
|
// Variables to hold data from custom textboxes
|
||||||
|
char testString[50] = "test value";
|
||||||
|
int testNumber = 1234;
|
||||||
|
char mqtt_server[40];
|
||||||
|
int mqtt_port = 1883;
|
||||||
|
char mqtt_username[34] = "";
|
||||||
|
char mqtt_password[34] = "";
|
||||||
|
char mqtt_topic[34] = "";
|
||||||
|
|
||||||
|
void setupWifi(const char *setupWifi, bool resetOnStart)
|
||||||
|
{
|
||||||
|
// Change to true when testing to force configuration every time we run
|
||||||
|
bool forceConfig = false;
|
||||||
|
wm.setConfigPortalTimeout(60);
|
||||||
|
// Reset settings (only for development)
|
||||||
|
if (resetOnStart)
|
||||||
|
{
|
||||||
|
wm.resetSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set config save notify callback
|
||||||
|
wm.setSaveConfigCallback(saveConfigCallback);
|
||||||
|
|
||||||
|
// Set callback that gets called when connecting to previous WiFi fails, and enters Access Point mode
|
||||||
|
wm.setAPCallback(configModeCallback);
|
||||||
|
|
||||||
|
// Custom elements
|
||||||
|
WiFiManagerParameter custom_mqtt_server("server", "mqtt server", mqtt_server, 40);
|
||||||
|
WiFiManagerParameter custom_mqtt_username("username", "mqtt username", mqtt_username, 50);
|
||||||
|
WiFiManagerParameter custom_mqtt_password("password", "mqtt password", mqtt_password, 50);
|
||||||
|
WiFiManagerParameter custom_mqtt_topic("topic", "mqtt topic", mqtt_topic, 50);
|
||||||
|
|
||||||
|
// Text box (String) - 50 characters maximum
|
||||||
|
WiFiManagerParameter custom_text_box("key_text", "Enter your string here", testString, 50);
|
||||||
|
|
||||||
|
// Need to convert numerical input to string to display the default value.
|
||||||
|
char convertedValue[6];
|
||||||
|
sprintf(convertedValue, "%d", testNumber);
|
||||||
|
|
||||||
|
// Text box (Number) - 7 characters maximum
|
||||||
|
WiFiManagerParameter custom_text_box_num("key_num", "Enter your number here", convertedValue, 7);
|
||||||
|
char convertedMqttPort[6];
|
||||||
|
sprintf(convertedMqttPort, "%d", mqtt_port);
|
||||||
|
WiFiManagerParameter custom_mqtt_port("port", "mqtt port", convertedMqttPort, 6);
|
||||||
|
|
||||||
|
// Add all defined parameters
|
||||||
|
wm.addParameter(&custom_text_box);
|
||||||
|
wm.addParameter(&custom_text_box_num);
|
||||||
|
wm.addParameter(&custom_mqtt_server);
|
||||||
|
wm.addParameter(&custom_mqtt_port);
|
||||||
|
wm.addParameter(&custom_mqtt_username);
|
||||||
|
wm.addParameter(&custom_mqtt_password);
|
||||||
|
wm.addParameter(&custom_mqtt_topic);
|
||||||
|
|
||||||
|
if (forceConfig)
|
||||||
|
// Run if we need a configuration
|
||||||
|
{
|
||||||
|
if (!wm.startConfigPortal(setupWifi))
|
||||||
|
{
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_WARN, "Wifi", "failed to connect and hit timeout");
|
||||||
|
delay(3000);
|
||||||
|
// reset and try again, or maybe put it to deep sleep
|
||||||
|
ESP.restart();
|
||||||
|
delay(5000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!wm.autoConnect(setupWifi))
|
||||||
|
{
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_WARN, "Wifi", "failed to connect and hit timeout");
|
||||||
|
delay(3000);
|
||||||
|
// if we still have not connected restart and try all over again
|
||||||
|
ESP.restart();
|
||||||
|
delay(5000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we get here, we are connected to the WiFi
|
||||||
|
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "Wifi", "");
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "Wifi", "WiFi connected");
|
||||||
|
String message = "IP address: " + String(WiFi.localIP());
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "Wifi", message.c_str());
|
||||||
|
|
||||||
|
// Lets deal with the user config values
|
||||||
|
|
||||||
|
// Copy the string value
|
||||||
|
strncpy(testString, custom_text_box.getValue(), sizeof(testString));
|
||||||
|
Serial.print("testString: ");
|
||||||
|
Serial.println(testString);
|
||||||
|
|
||||||
|
// Convert the number value
|
||||||
|
testNumber = atoi(custom_text_box_num.getValue());
|
||||||
|
Serial.print("testNumber: ");
|
||||||
|
Serial.println(testNumber);
|
||||||
|
|
||||||
|
mqtt_port = atoi(custom_mqtt_port.getValue());
|
||||||
|
strncpy(mqtt_server, custom_mqtt_server.getValue(), sizeof(mqtt_server));
|
||||||
|
strncpy(mqtt_username, custom_mqtt_username.getValue(), sizeof(mqtt_username));
|
||||||
|
strncpy(mqtt_password, custom_mqtt_password.getValue(), sizeof(mqtt_password));
|
||||||
|
strncpy(mqtt_topic, custom_mqtt_topic.getValue(), sizeof(mqtt_topic));
|
||||||
|
|
||||||
|
|
||||||
|
// Save the custom parameters to FS
|
||||||
|
if (shouldSaveConfig)
|
||||||
|
{
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "Wifi", "Save config");
|
||||||
|
saveConfigFile();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void saveConfigCallback()
|
||||||
|
// Callback notifying us of the need to save configuration
|
||||||
|
{
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "Wifi", "Should save config");
|
||||||
|
shouldSaveConfig = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void configModeCallback(WiFiManager *myWiFiManager)
|
||||||
|
// Called when config mode launched
|
||||||
|
{
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "Wifi", "Entered Configuration Mode");
|
||||||
|
|
||||||
|
String message = "Config SSID: " + String(myWiFiManager->getConfigPortalSSID());
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "Wifi", message.c_str());
|
||||||
|
|
||||||
|
|
||||||
|
message = "Config IP Address: " + String(WiFi.softAPIP());
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "Wifi", message.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void saveConfigFile()
|
||||||
|
// Save Config in JSON format
|
||||||
|
{
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "Wifi", "Saving configuration...");
|
||||||
|
config.setMqttConfig(mqtt_server, mqtt_port, mqtt_username, mqtt_password, mqtt_topic);
|
||||||
|
config.writeData();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
#ifndef WIFI_H
|
||||||
|
#define WIFI_H
|
||||||
|
|
||||||
|
// File System Library
|
||||||
|
#include <FS.h>
|
||||||
|
// SPI Flash Syetem Library
|
||||||
|
#include <SPIFFS.h>
|
||||||
|
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <WiFiManager.h> // https://github.com/tzapu/WiFiManager
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
#include "config.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
extern WiFiManager wm;
|
||||||
|
|
||||||
|
// Flag for saving data
|
||||||
|
extern bool shouldSaveConfig;
|
||||||
|
|
||||||
|
|
||||||
|
void setupWifi(const char *apName, bool resetOnStart);
|
||||||
|
void saveConfigCallback();
|
||||||
|
void configModeCallback(WiFiManager *myWiFiManager);
|
||||||
|
bool loadConfigFile();
|
||||||
|
void saveConfigFile();
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* WIFI_H */
|
||||||
|
|
@ -110,3 +110,20 @@ void loop() {
|
||||||
|
|
||||||
// delay(3000);
|
// delay(3000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Calc battery:
|
||||||
|
float voltage = analogRead(35) / 4096.0 * 7.46;
|
||||||
|
uint8_t percentage = 100;
|
||||||
|
if (voltage > 1) {
|
||||||
|
// Only display if there is a valid reading
|
||||||
|
Serial.println("Voltage = " + String(voltage));
|
||||||
|
percentage = 2836.9625 * pow(voltage, 4) - 43987.4889 * pow(voltage, 3) + 255233.8134 * pow(voltage, 2) - 656689.7123 * voltage + 632041.7303;
|
||||||
|
if (voltage >= 4.20) percentage = 100;
|
||||||
|
if (voltage <= 3.50) percentage = 0;
|
||||||
|
Serial.println("Percentage = " + String(percentage));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
Loading…
Reference in New Issue