mqtt and system tabs
This commit is contained in:
parent
0c74411808
commit
3aabf4f8c1
@ -20,7 +20,6 @@ board_build.filesystem = littlefs
|
||||
extra_scripts =
|
||||
post:scripts/build_interface.py
|
||||
lib_deps =
|
||||
adafruit/Adafruit NeoPixel@^1.11.0
|
||||
ottowinter/AsyncMqttClient-esphome@^0.8.6
|
||||
ottowinter/ESPAsyncWebServer-esphome@^3.1.0
|
||||
bblanchon/ArduinoJson@^6.21.3
|
||||
|
@ -1,10 +1,13 @@
|
||||
#include "app/routes.h"
|
||||
#include "infra/eth.h"
|
||||
#include "infra/httpServer.h"
|
||||
#include "infra/mqtt.h"
|
||||
#include "infra/relay.h"
|
||||
#include "infra/fs.h"
|
||||
#include "config/config.h"
|
||||
#include "utils/print.h"
|
||||
#include "utils/settings.h"
|
||||
#include "utils/utils.h"
|
||||
|
||||
void handleDoorOpen(AsyncWebServerRequest *request) {
|
||||
relayTurnOn();
|
||||
@ -31,7 +34,7 @@ void getFeatures(AsyncWebServerRequest *request) {
|
||||
}
|
||||
|
||||
void intercomStatus(AsyncWebServerRequest* request) {
|
||||
AsyncJsonResponse* response = new AsyncJsonResponse(false, MAX_AP_STATUS_SIZE);
|
||||
AsyncJsonResponse* response = new AsyncJsonResponse(false, MAX_INTERCOM_STATUS_SIZE);
|
||||
JsonObject root = response->getRoot();
|
||||
|
||||
root["status"] = 0;
|
||||
@ -46,25 +49,8 @@ void intercomStatus(AsyncWebServerRequest* request) {
|
||||
void networkStatus(AsyncWebServerRequest* request) {
|
||||
AsyncJsonResponse* response = new AsyncJsonResponse(false, MAX_NETWORK_STATUS_SIZE);
|
||||
JsonObject root = response->getRoot();
|
||||
wl_status_t status = WL_CONNECTED;
|
||||
|
||||
root["status"] = (uint8_t)status;
|
||||
if (status == WL_CONNECTED) {
|
||||
root["local_ip"] = ETH.localIP().toString();
|
||||
IPv6Address localIPv6 = ETH.localIPv6();
|
||||
if (!(localIPv6 == IPv6Address()))
|
||||
root["local_ip_v6"] = ETH.localIPv6().toString();
|
||||
root["mac_address"] = ETH.macAddress();
|
||||
root["full_duplex"] = ETH.fullDuplex();
|
||||
root["link_speed"] = ETH.linkSpeed();
|
||||
root["link_up"] = ETH.linkUp();
|
||||
root["network_id"] = ETH.networkID();
|
||||
root["subnet_mask"] = ETH.subnetMask().toString();
|
||||
root["gateway_ip"] = ETH.gatewayIP().toString();
|
||||
IPAddress dnsIP = ETH.dnsIP();
|
||||
if (dnsIP)
|
||||
root["dns_ip"] = dnsIP.toString();
|
||||
}
|
||||
getEthStatus(root);
|
||||
|
||||
response->setLength();
|
||||
request->send(response);
|
||||
@ -79,20 +65,14 @@ void scanNetworks(AsyncWebServerRequest* request) {
|
||||
}
|
||||
|
||||
static void networkSettingsRead(AsyncWebServerRequest* request) {
|
||||
AsyncJsonResponse* response = new AsyncJsonResponse(false, MAX_NETWORK_STATUS_SIZE);
|
||||
AsyncJsonResponse* response = new AsyncJsonResponse(false, MAX_NETWORK_SETTINGS_SIZE);
|
||||
DynamicJsonDocument doc(1024);
|
||||
|
||||
bool success = readJsonVariantFromFile(NETWORK_SETTINGS_PATH, doc);
|
||||
JsonVariant root = doc.as<JsonVariant>();
|
||||
|
||||
if (!success) {
|
||||
root["static_ip_config"] = false;
|
||||
root["local_ip"] = ETH.localIP().toString();
|
||||
root["gateway_ip"] = ETH.gatewayIP().toString();
|
||||
root["subnet_mask"] = ETH.subnetMask().toString();
|
||||
root["dns_ip"] = ETH.dnsIP().toString();
|
||||
root["dns_ip_2"] = ETH.dnsIP(1).toString();
|
||||
}
|
||||
if (!success)
|
||||
getDefaultEthConf(root);
|
||||
|
||||
response->setLength();
|
||||
|
||||
@ -101,24 +81,21 @@ static void networkSettingsRead(AsyncWebServerRequest* request) {
|
||||
request->send(200, "application/json", jsonString.c_str());
|
||||
}
|
||||
|
||||
static void networkSettingsUpdate(AsyncWebServerRequest* request, JsonVariant &json) {
|
||||
if (!json.is<JsonVariant>()) {
|
||||
static void networkSettingsUpdate(AsyncWebServerRequest *request,
|
||||
uint8_t *data, size_t len, size_t index, size_t total) {
|
||||
DynamicJsonDocument jsonDoc(MAX_NETWORK_SETTINGS_SIZE);
|
||||
String jsonStr = requestDataToStr(data, len);
|
||||
DeserializationError error = deserializeJson(jsonDoc, jsonStr);
|
||||
|
||||
if (!jsonDoc.is<JsonVariant>()) {
|
||||
request->send(400);
|
||||
return;
|
||||
}
|
||||
|
||||
JsonVariant root = json.as<JsonVariant>();
|
||||
JsonVariant root = jsonDoc.as<JsonVariant>();
|
||||
|
||||
bool success = writeJsonVariantToFile(NETWORK_SETTINGS_PATH, root);
|
||||
|
||||
setEthConfig(
|
||||
root["static_ip_config"].as<bool>(),
|
||||
root["local_ip"].as<String>(),
|
||||
root["gateway_ip"].as<String>(),
|
||||
root["subnet_mask"].as<String>(),
|
||||
root["dns_ip"].as<String>()
|
||||
);
|
||||
|
||||
if (success) {
|
||||
String jsonString;
|
||||
serializeJson(root, jsonString);
|
||||
@ -126,6 +103,106 @@ static void networkSettingsUpdate(AsyncWebServerRequest* request, JsonVariant &j
|
||||
}
|
||||
else
|
||||
request->send(500, "text/plain", "Network settings not updated");
|
||||
|
||||
configureEth(
|
||||
root["static_ip_config"].as<bool>(),
|
||||
root["local_ip"].as<String>(),
|
||||
root["gateway_ip"].as<String>(),
|
||||
root["subnet_mask"].as<String>(),
|
||||
root["dns_ip"].as<String>()
|
||||
);
|
||||
}
|
||||
|
||||
static void mqttStatus(AsyncWebServerRequest* request) {
|
||||
AsyncJsonResponse* response = new AsyncJsonResponse(false, MAX_MQTT_STATUS_SIZE);
|
||||
JsonObject root = response->getRoot();
|
||||
|
||||
root["enabled"] = getMqttEnabled();
|
||||
root["connected"] = getMqttClient().connected();
|
||||
root["client_id"] = getMqttClient().getClientId();
|
||||
root["disconnect_reason"] = (uint8_t)getMqttDisconnectReason();
|
||||
|
||||
response->setLength();
|
||||
request->send(response);
|
||||
}
|
||||
|
||||
static void mqttSettingsRead(AsyncWebServerRequest* request) {
|
||||
AsyncJsonResponse* response = new AsyncJsonResponse(false, MAX_MQTT_SETTINGS_SIZE);
|
||||
DynamicJsonDocument doc(1024);
|
||||
|
||||
bool success = readJsonVariantFromFile(MQTT_SETTINGS_PATH, doc);
|
||||
JsonVariant root = doc.as<JsonVariant>();
|
||||
|
||||
if (!success)
|
||||
getDefaultMqttConf(root);
|
||||
|
||||
response->setLength();
|
||||
|
||||
String jsonString;
|
||||
serializeJson(root, jsonString);
|
||||
request->send(200, "application/json", jsonString.c_str());
|
||||
}
|
||||
|
||||
static void mqttSettingsUpdate(AsyncWebServerRequest *request,
|
||||
uint8_t *data, size_t len, size_t index, size_t total) {
|
||||
DynamicJsonDocument jsonDoc(MAX_MQTT_SETTINGS_SIZE);
|
||||
String jsonStr = requestDataToStr(data, len);
|
||||
DeserializationError error = deserializeJson(jsonDoc, jsonStr);
|
||||
|
||||
if (!jsonDoc.is<JsonVariant>() || error) {
|
||||
request->send(400);
|
||||
return;
|
||||
}
|
||||
|
||||
JsonVariant root = jsonDoc.as<JsonVariant>();
|
||||
|
||||
bool fileLoaded = writeJsonVariantToFile(MQTT_SETTINGS_PATH, root);
|
||||
bool enabled = root["enabled"].as<bool>();
|
||||
|
||||
bool mqttConfigured = configureMqtt(
|
||||
root["enabled"].as<bool>(),
|
||||
root["host"].as<String>(),
|
||||
root["port"].as<uint16_t>(),
|
||||
root["username"].as<String>(),
|
||||
root["password"].as<String>(),
|
||||
root["client_id"].as<String>(),
|
||||
root["keep_alive"].as<uint16_t>(),
|
||||
root["clean_session"].as<bool>(),
|
||||
root["max_topic_length"].as<uint16_t>()
|
||||
);
|
||||
|
||||
if (!fileLoaded) {
|
||||
request->send(500, "text/plain", "MQTT settings not updated");
|
||||
} else if (!mqttConfigured && enabled) {
|
||||
request->send(404, "text/plain", "MQTT settings not configured");
|
||||
} else {
|
||||
String jsonString;
|
||||
serializeJson(root, jsonString);
|
||||
request->send(200, "application/json", jsonString.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void systemStatus(AsyncWebServerRequest* request) {
|
||||
AsyncJsonResponse* response = new AsyncJsonResponse(false, MAX_ESP_STATUS_SIZE);
|
||||
JsonObject root = response->getRoot();
|
||||
|
||||
root["esp_platform"] = "esp32";
|
||||
root["max_alloc_heap"] = ESP.getMaxAllocHeap();
|
||||
root["psram_size"] = ESP.getPsramSize();
|
||||
root["free_psram"] = ESP.getFreePsram();
|
||||
root["cpu_freq_mhz"] = ESP.getCpuFreqMHz();
|
||||
root["free_heap"] = ESP.getFreeHeap();
|
||||
root["sketch_size"] = ESP.getSketchSize();
|
||||
root["free_sketch_space"] = ESP.getFreeSketchSpace();
|
||||
root["sdk_version"] = ESP.getSdkVersion();
|
||||
root["flash_chip_size"] = ESP.getFlashChipSize();
|
||||
root["flash_chip_speed"] = ESP.getFlashChipSpeed();
|
||||
|
||||
root["fs_total"] = LittleFS.totalBytes();
|
||||
root["fs_used"] = LittleFS.usedBytes();
|
||||
|
||||
response->setLength();
|
||||
request->send(response);
|
||||
}
|
||||
|
||||
void handleDoorStatus(AsyncWebServerRequest *request) {
|
||||
@ -133,14 +210,25 @@ void handleDoorStatus(AsyncWebServerRequest *request) {
|
||||
request->send(200, "text/plain", "OK");
|
||||
}
|
||||
|
||||
void handleBodyRequest(AsyncWebServer& server, const char* uri, WebRequestMethodComposite method, \
|
||||
|
||||
void handleBodyRequest(AsyncWebServer& server, const char* uri, WebRequestMethodComposite method,
|
||||
ArJsonRequestHandlerFunction onRequest) {
|
||||
AsyncCallbackJsonWebHandler* handler = \
|
||||
new AsyncCallbackJsonWebHandler(uri, networkSettingsUpdate);
|
||||
new AsyncCallbackJsonWebHandler(uri, onRequest);
|
||||
handler->setMethod(method);
|
||||
server.addHandler(handler);
|
||||
}
|
||||
|
||||
void restartNow(AsyncWebServerRequest *request) {
|
||||
request->send(200, "text/plain", "OK");
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
void factoryReset(AsyncWebServerRequest *request) {
|
||||
deleteFilesInDir(FS_CONFIG_DIRECTORY);
|
||||
restartNow(request);
|
||||
}
|
||||
|
||||
void initRoutes() {
|
||||
AsyncWebServer& server = getServer();
|
||||
server.on("/api/v1/door/open", handleDoorOpen);
|
||||
@ -150,7 +238,15 @@ void initRoutes() {
|
||||
|
||||
server.on("/api/v1/networkStatus", networkStatus);
|
||||
server.on("/api/v1/networkSettings", HTTP_GET, networkSettingsRead);
|
||||
handleBodyRequest(server, "/api/v1/networkSettings", HTTP_POST, networkSettingsUpdate);
|
||||
server.on("/api/v1/networkSettings", HTTP_POST, [](AsyncWebServerRequest *request) {}, NULL, networkSettingsUpdate);
|
||||
|
||||
server.on("/api/v1/intercomStatus", intercomStatus);
|
||||
|
||||
server.on("/api/v1/mqttStatus", mqttStatus);
|
||||
server.on("/api/v1/mqttSettings", HTTP_GET, mqttSettingsRead);
|
||||
server.on("/api/v1/mqttSettings", HTTP_POST, [](AsyncWebServerRequest *request) {}, NULL, mqttSettingsUpdate);
|
||||
|
||||
server.on("/api/v1/systemStatus", systemStatus);
|
||||
server.on("/api/v1/restart", restartNow);
|
||||
server.on("/api/v1/factoryReset", factoryReset);
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
#include <ArduinoJson.h>
|
||||
#include <AsyncJson.h>
|
||||
#include <FS.h>
|
||||
|
||||
void initRoutes();
|
@ -1,11 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#define DEFAULT_STATIC_LOCAL_IP IPAddress(192, 168, 1, 150)
|
||||
#define DEFAULT_STATIC_GATEWAY IPAddress(192, 168, 1, 1)
|
||||
#define DEFAULT_STATIC_SUBNET IPAddress(255, 255, 255, 0)
|
||||
#define FACTORY_STATIC_LOCAL_IP IPAddress(192, 168, 1, 150)
|
||||
#define FACTORY_STATIC_GATEWAY IPAddress(192, 168, 1, 1)
|
||||
#define FACTORY_STATIC_SUBNET IPAddress(255, 255, 255, 0)
|
||||
|
||||
#define MQTT_HOST IPAddress(192, 168, 1, 173)
|
||||
#define MQTT_PORT 1883
|
||||
#define FACTORY_MQTT_ENABLED false
|
||||
#define FACTORY_MQTT_HOST ""
|
||||
#define FACTORY_MQTT_PORT 1883
|
||||
#define FACTORY_MQTT_USERNAME ""
|
||||
#define FACTORY_MQTT_PASSWORD ""
|
||||
#define FACTORY_MQTT_CLIENT_ID "#{platform}-#{unique_id}"
|
||||
#define FACTORY_MQTT_KEEP_ALIVE 16
|
||||
#define FACTORY_MQTT_CLEAN_SESSION true
|
||||
#define FACTORY_MQTT_MAX_TOPIC_LENGTH 128
|
||||
|
||||
#define SERIAL_NUMBER "4823"
|
||||
|
||||
@ -21,13 +28,18 @@
|
||||
#define DOOR_SENS_PIN 114
|
||||
|
||||
#define DATA_PIN 12
|
||||
#define DATA_PERIOD 240 // microseconds
|
||||
#define DATA_PERIOD 120 // microseconds
|
||||
|
||||
#define PRINT_RAW_SIGNAL_FLAG 0
|
||||
#define PRINT_RAW_SIGNAL_FLAG 1
|
||||
|
||||
#define MAX_FEATURES_SIZE 256
|
||||
#define MAX_AP_STATUS_SIZE 1024
|
||||
#define MAX_NETWORK_STATUS_SIZE 1024
|
||||
#define MAX_NETWORK_SETTINGS_SIZE 1024
|
||||
#define MAX_INTERCOM_STATUS_SIZE 1024
|
||||
#define MAX_MQTT_STATUS_SIZE 1024
|
||||
#define MAX_MQTT_SETTINGS_SIZE 1024
|
||||
#define MAX_ESP_STATUS_SIZE 1024
|
||||
|
||||
#define NETWORK_SETTINGS_PATH "/config/networkSettings.json"
|
||||
#define FS_CONFIG_DIRECTORY "/config"
|
||||
#define NETWORK_SETTINGS_PATH "/config/networkSettings.json"
|
||||
#define MQTT_SETTINGS_PATH "/config/mqttSettings.json"
|
@ -38,7 +38,7 @@ void receiveData(int data) {
|
||||
previousData = data;
|
||||
}
|
||||
|
||||
void changeState(State state, bool resetCountersFlag=true) {
|
||||
void changeState(State state, bool resetCountersFlag) {
|
||||
currentState = state;
|
||||
|
||||
switch (state) {
|
||||
@ -139,4 +139,8 @@ void updateStateMachine(int data) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void initStateMachine() {
|
||||
changeState(CONNECTED);
|
||||
}
|
@ -19,5 +19,7 @@ enum State {
|
||||
|
||||
void resetCounters();
|
||||
void updateStateMachine(int data);
|
||||
void initStateMachine();
|
||||
void changeState(State state, bool resetCountersFlag=true);
|
||||
|
||||
#endif // STATE_MACHINE_H
|
@ -1,12 +1,11 @@
|
||||
#include <ArduinoJson.h>
|
||||
#include "infra/eth.h"
|
||||
#include "infra/fs.h"
|
||||
#include "infra/mqtt.h"
|
||||
#include "config/config.h"
|
||||
#include "utils/print.h"
|
||||
|
||||
extern bool eth_connected;
|
||||
TimerHandle_t ethReconnectTimer;
|
||||
wl_status_t status;
|
||||
|
||||
void WiFiEvent(WiFiEvent_t event)
|
||||
{
|
||||
@ -19,6 +18,7 @@ void WiFiEvent(WiFiEvent_t event)
|
||||
break;
|
||||
case ARDUINO_EVENT_ETH_CONNECTED:
|
||||
Serial.println("ETH Connected");
|
||||
status = WL_CONNECTED;
|
||||
break;
|
||||
case ARDUINO_EVENT_ETH_GOT_IP:
|
||||
Serial.print("ETH MAC: ");
|
||||
@ -31,17 +31,14 @@ void WiFiEvent(WiFiEvent_t event)
|
||||
Serial.print(", ");
|
||||
Serial.print(ETH.linkSpeed());
|
||||
Serial.println("Mbps");
|
||||
eth_connected = true;
|
||||
delay(2000);
|
||||
connectToMqtt();
|
||||
break;
|
||||
case ARDUINO_EVENT_ETH_DISCONNECTED:
|
||||
Serial.println("ETH Disconnected");
|
||||
eth_connected = false;
|
||||
status = WL_DISCONNECTED;
|
||||
break;
|
||||
case ARDUINO_EVENT_ETH_STOP:
|
||||
Serial.println("ETH Stopped");
|
||||
eth_connected = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -67,15 +64,12 @@ void WiFiEvent(WiFiEvent_t event)
|
||||
Serial.print(", ");
|
||||
Serial.print(ETH.linkSpeed());
|
||||
Serial.println("Mbps");
|
||||
eth_connected = true;
|
||||
break;
|
||||
case SYSTEM_EVENT_ETH_DISCONNECTED:
|
||||
Serial.println("ETH Disconnected");
|
||||
eth_connected = false;
|
||||
break;
|
||||
case SYSTEM_EVENT_ETH_STOP:
|
||||
Serial.println("ETH Stopped");
|
||||
eth_connected = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -83,6 +77,75 @@ void WiFiEvent(WiFiEvent_t event)
|
||||
#endif
|
||||
}
|
||||
|
||||
void configureEth(bool isStatic, String localIp, String gateway,
|
||||
String subnet, String dns1, String dns2) {
|
||||
IPAddress newLocalIp = IPAddress();
|
||||
IPAddress newGateway = IPAddress();
|
||||
IPAddress newSubnet = IPAddress();
|
||||
IPAddress newDns1 = IPAddress();
|
||||
IPAddress newDns2 = IPAddress();
|
||||
|
||||
newLocalIp.fromString(localIp);
|
||||
newGateway.fromString(gateway);
|
||||
newSubnet.fromString(subnet);
|
||||
newDns1.fromString(dns1);
|
||||
newDns2.fromString(dns2);
|
||||
|
||||
if (isStatic)
|
||||
ETH.config(
|
||||
newLocalIp,
|
||||
newGateway,
|
||||
newSubnet,
|
||||
newDns1,
|
||||
newDns2
|
||||
);
|
||||
else {
|
||||
//ESP.restart();
|
||||
ETH.config((uint32_t)0, (uint32_t)0, (uint32_t)0);
|
||||
}
|
||||
}
|
||||
|
||||
void configureEth(JsonVariant& root) {
|
||||
configureEth(
|
||||
root["static_ip_config"].as<bool>(),
|
||||
root["local_ip"].as<String>(),
|
||||
root["gateway_ip"].as<String>(),
|
||||
root["subnet_mask"].as<String>(),
|
||||
root["dns_ip"].as<String>()
|
||||
);
|
||||
}
|
||||
|
||||
void getDefaultEthConf(JsonVariant& root) {
|
||||
root["static_ip_config"] = true;
|
||||
root["local_ip"] = ETH.localIP().toString();
|
||||
root["gateway_ip"] = ETH.gatewayIP().toString();
|
||||
root["subnet_mask"] = ETH.subnetMask().toString();
|
||||
root["dns_ip"] = ETH.dnsIP().toString();
|
||||
root["dns_ip_2"] = ETH.dnsIP(1).toString();
|
||||
}
|
||||
|
||||
void getEthStatus(JsonObject& root) {
|
||||
root["status"] = (uint8_t)status;
|
||||
|
||||
if (status == WL_CONNECTED) {
|
||||
root["local_ip"] = ETH.localIP().toString();
|
||||
IPv6Address localIPv6 = ETH.localIPv6();
|
||||
if (!(localIPv6 == IPv6Address()))
|
||||
root["local_ip_v6"] = ETH.localIPv6().toString();
|
||||
root["mac_address"] = ETH.macAddress();
|
||||
root["full_duplex"] = ETH.fullDuplex();
|
||||
root["link_speed"] = ETH.linkSpeed();
|
||||
root["link_up"] = ETH.linkUp();
|
||||
root["network_id"] = ETH.networkID();
|
||||
root["subnet_mask"] = ETH.subnetMask().toString();
|
||||
root["gateway_ip"] = ETH.gatewayIP().toString();
|
||||
|
||||
IPAddress dnsIP = ETH.dnsIP();
|
||||
if (dnsIP)
|
||||
root["dns_ip"] = dnsIP.toString();
|
||||
}
|
||||
}
|
||||
|
||||
bool loadEthConfig() {
|
||||
DynamicJsonDocument doc(1024);
|
||||
|
||||
@ -93,13 +156,7 @@ bool loadEthConfig() {
|
||||
|
||||
JsonVariant root = doc.as<JsonVariant>();
|
||||
|
||||
setEthConfig(
|
||||
root["static_ip_config"].as<bool>(),
|
||||
root["local_ip"].as<String>(),
|
||||
root["gateway_ip"].as<String>(),
|
||||
root["subnet_mask"].as<String>(),
|
||||
root["dns_ip"].as<String>()
|
||||
);
|
||||
configureEth(root);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -122,17 +179,16 @@ void initEth() {
|
||||
ETH_TYPE,
|
||||
ETH_CLK_MODE);
|
||||
|
||||
if (!loadEthConfig() && DEFAULT_STATIC_LOCAL_IP) {
|
||||
if (!loadEthConfig() && FACTORY_STATIC_LOCAL_IP) {
|
||||
ETH.config(
|
||||
DEFAULT_STATIC_LOCAL_IP,
|
||||
DEFAULT_STATIC_GATEWAY,
|
||||
DEFAULT_STATIC_SUBNET
|
||||
FACTORY_STATIC_LOCAL_IP,
|
||||
FACTORY_STATIC_GATEWAY,
|
||||
FACTORY_STATIC_SUBNET
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void testClient(const char * host, uint16_t port)
|
||||
{
|
||||
void testClient(const char * host, uint16_t port) {
|
||||
Serial.print("\nconnecting to ");
|
||||
Serial.println(host);
|
||||
|
||||
@ -151,29 +207,13 @@ void testClient(const char * host, uint16_t port)
|
||||
client.stop();
|
||||
}
|
||||
|
||||
void setEthConfig(bool isStatic, String localIp, String gateway,
|
||||
String subnet, String dns1, String dns2) {
|
||||
IPAddress newLocalIp = IPAddress();
|
||||
IPAddress newGateway = IPAddress();
|
||||
IPAddress newSubnet = IPAddress();
|
||||
IPAddress newDns1 = IPAddress();
|
||||
IPAddress newDns2 = IPAddress();
|
||||
bool checkHost(const char* host, uint16_t port) {
|
||||
WiFiClient client;
|
||||
|
||||
newLocalIp.fromString(localIp);
|
||||
newGateway.fromString(gateway);
|
||||
newSubnet.fromString(subnet);
|
||||
newDns1.fromString(dns1);
|
||||
newDns2.fromString(dns2);
|
||||
|
||||
if (isStatic)
|
||||
ETH.config(
|
||||
newLocalIp,
|
||||
newGateway,
|
||||
newSubnet,
|
||||
newDns1,
|
||||
newDns2
|
||||
);
|
||||
else {
|
||||
ETH.config((uint32_t)0, (uint32_t)0, (uint32_t)0);
|
||||
}
|
||||
if (client.connect(host, port)) {
|
||||
client.stop();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <ETH.h>
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
/*
|
||||
* ETH_CLOCK_GPIO0_IN - default: external clock from crystal oscillator
|
||||
@ -30,11 +31,15 @@
|
||||
void WiFiEvent(WiFiEvent_t event);
|
||||
void initEth();
|
||||
void testClient(const char * host, uint16_t port);
|
||||
void setEthConfig(
|
||||
bool checkHost(const char* host, uint16_t port);
|
||||
void getEthStatus(JsonObject& root);
|
||||
void configureEth(
|
||||
bool isStatic,
|
||||
String localIp,
|
||||
String gateway,
|
||||
String subnet,
|
||||
String dns1="",
|
||||
String dns2=""
|
||||
);
|
||||
);
|
||||
void configureEth(JsonVariant& root);
|
||||
void getDefaultEthConf(JsonVariant& root);
|
@ -24,7 +24,7 @@ bool readJsonVariantFromFile(const char* file_path, DynamicJsonDocument& jsonDoc
|
||||
}
|
||||
|
||||
String fileContent = file.readString();
|
||||
println("Reading config: ", fileContent);
|
||||
println("Reading config: ", file_path, ", content:", fileContent);
|
||||
|
||||
DeserializationError error = deserializeJson(jsonDoc, fileContent);
|
||||
|
||||
@ -62,10 +62,32 @@ bool writeJsonVariantToFile(const char* file_path, JsonVariant& jsonVariant) {
|
||||
|
||||
String jsonString;
|
||||
serializeJson(jsonVariant, jsonString);
|
||||
println("Writing config: ", jsonString);
|
||||
println("Writing config: ", file_path, ", content:", jsonString);
|
||||
file.print(jsonString);
|
||||
|
||||
file.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void deleteFilesInDir(const char* path) {
|
||||
File dir = LittleFS.open(path);
|
||||
if (!dir.isDirectory()) {
|
||||
Serial.println("Not a directory");
|
||||
return;
|
||||
}
|
||||
|
||||
File file = dir.openNextFile();
|
||||
while (file) {
|
||||
String fullPath = String(path) + '/' + String(file.name());
|
||||
if (file.isDirectory()) {
|
||||
deleteFilesInDir(fullPath.c_str());
|
||||
} else {
|
||||
file.close();
|
||||
LittleFS.remove(fullPath);
|
||||
}
|
||||
|
||||
file = dir.openNextFile();
|
||||
}
|
||||
dir.close();
|
||||
}
|
||||
|
@ -4,4 +4,5 @@
|
||||
|
||||
void initFileSystem();
|
||||
bool readJsonVariantFromFile(const char* filename, DynamicJsonDocument& jsonDoc);
|
||||
bool writeJsonVariantToFile(const char* filename, JsonVariant& jsonObj);
|
||||
bool writeJsonVariantToFile(const char* filename, JsonVariant& jsonObj);
|
||||
void deleteFilesInDir(const char* path);
|
0
src/infra/intercom.cpp
Normal file
0
src/infra/intercom.cpp
Normal file
0
src/infra/intercom.h
Normal file
0
src/infra/intercom.h
Normal file
@ -1,16 +1,23 @@
|
||||
#include <Arduino.h>
|
||||
#include <ETH.h>
|
||||
|
||||
#include "config/config.h"
|
||||
#include "infra/mqtt.h"
|
||||
#include "infra/eth.h"
|
||||
#include "infra/fs.h"
|
||||
#include "utils/settings.h"
|
||||
|
||||
AsyncMqttClient mqttClient;
|
||||
TimerHandle_t mqttReconnectTimer;
|
||||
AsyncMqttClientDisconnectReason mqttDisconnectReason;
|
||||
|
||||
void connectToMqtt() {
|
||||
Serial.println("Connecting to MQTT...");
|
||||
mqttClient.connect();
|
||||
}
|
||||
DynamicJsonDocument mqttConf(1024);
|
||||
bool mqttConnected = false;
|
||||
bool mqttEnabled = true;
|
||||
|
||||
// Pointers to hold retained copies of the mqtt client connection strings.
|
||||
// This is required as AsyncMqttClient holds refrences to the supplied connection strings.
|
||||
char* retainedHost;
|
||||
char* retainedClientId;
|
||||
char* retainedUsername;
|
||||
char* retainedPassword;
|
||||
|
||||
void publishToMQTT(const char* topic, const char* message) {
|
||||
mqttClient.publish(topic, 2, true, message);
|
||||
@ -34,24 +41,25 @@ void publishToMQTT(const char* topic, bool message) {
|
||||
}
|
||||
|
||||
void onMqttConnect(bool sessionPresent) {
|
||||
Serial.println("Connected to MQTT.");
|
||||
Serial.print("Session present: ");
|
||||
Serial.println(sessionPresent);
|
||||
Serial.println("Connected to MQTT.");
|
||||
Serial.print("Session present: ");
|
||||
Serial.println(sessionPresent);
|
||||
|
||||
publishToMQTT(MAC_ADDRESS_MQTT_TOPIC, ETH.macAddress().c_str());
|
||||
publishToMQTT(IP_ADDRESS_MQTT_TOPIC, ETH.localIP().toString().c_str());
|
||||
publishToMQTT(SERIAL_NUMBER_MQTT_TOPIC, SERIAL_NUMBER);
|
||||
mqttConnected = true;
|
||||
|
||||
//uint16_t packetIdSub = mqttClient.subscribe("esp32/led", 0);
|
||||
//Serial.print("Subscribing at QoS 0, packetId: ");
|
||||
//Serial.println(packetIdSub);
|
||||
publishToMQTT(MAC_ADDRESS_MQTT_TOPIC, ETH.macAddress().c_str());
|
||||
publishToMQTT(IP_ADDRESS_MQTT_TOPIC, ETH.localIP().toString().c_str());
|
||||
publishToMQTT(SERIAL_NUMBER_MQTT_TOPIC, SERIAL_NUMBER);
|
||||
|
||||
//uint16_t packetIdSub = mqttClient.subscribe("esp32/led", 0);
|
||||
//Serial.print("Subscribing at QoS 0, packetId: ");
|
||||
//Serial.println(packetIdSub);
|
||||
}
|
||||
|
||||
void onMqttDisconnect(AsyncMqttClientDisconnectReason reason) {
|
||||
Serial.println("Disconnected from MQTT.");
|
||||
if (WiFi.isConnected()) {
|
||||
xTimerStart(mqttReconnectTimer, 0);
|
||||
}
|
||||
mqttConnected = false;
|
||||
mqttDisconnectReason = reason;
|
||||
}
|
||||
|
||||
void onMqttSubscribe(uint16_t packetId, uint8_t qos) {
|
||||
@ -74,14 +82,157 @@ void onMqttPublish(uint16_t packetId) {
|
||||
Serial.println(packetId);
|
||||
}
|
||||
|
||||
void initMQTT() {
|
||||
mqttReconnectTimer = xTimerCreate("mqttTimer", pdMS_TO_TICKS(2000), pdFALSE, (void*)0, reinterpret_cast<TimerCallbackFunction_t>(connectToMqtt));
|
||||
AsyncMqttClient& getMqttClient() {
|
||||
return mqttClient;
|
||||
}
|
||||
|
||||
AsyncMqttClientDisconnectReason& getMqttDisconnectReason() {
|
||||
return mqttDisconnectReason;
|
||||
}
|
||||
|
||||
bool getMqttConnected() {
|
||||
return mqttConnected;
|
||||
}
|
||||
|
||||
bool getMqttEnabled() {
|
||||
return mqttEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retains a copy of the cstr provided in the pointer provided using dynamic allocation.
|
||||
*
|
||||
* Frees the pointer before allocation and leaves it as nullptr if cstr == nullptr.
|
||||
*/
|
||||
static char* retainCstr(const char* cstr, char** ptr) {
|
||||
// free up previously retained value if exists
|
||||
free(*ptr);
|
||||
*ptr = nullptr;
|
||||
|
||||
// dynamically allocate and copy cstr (if non null)
|
||||
if (cstr != nullptr) {
|
||||
*ptr = (char*)malloc(strlen(cstr) + 1);
|
||||
strcpy(*ptr, cstr);
|
||||
}
|
||||
|
||||
// return reference to pointer for convenience
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
void setMqttServer(String host, uint16_t port) {
|
||||
Serial.print("MQTT server: ");
|
||||
Serial.print(host);
|
||||
Serial.print(":");
|
||||
Serial.println(port);
|
||||
mqttClient.setServer(retainCstr(host.c_str(), &retainedHost), port);
|
||||
}
|
||||
|
||||
bool checkMqttHost(String host, uint16_t port) {
|
||||
if (!checkHost(host.c_str(), port)) {
|
||||
Serial.print("MQTT host is not responding: ");
|
||||
Serial.print(host);
|
||||
Serial.print(":");
|
||||
Serial.println(port);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool configureMqtt(bool enabled, String host, uint16_t port, String username, String password,
|
||||
String clientId, uint16_t keepAlive, bool cleanSession, uint16_t maxTopicLength) {
|
||||
if (!mqttEnabled) {
|
||||
mqttEnabled = enabled;
|
||||
return checkMqttHost(host, port);
|
||||
}
|
||||
|
||||
mqttEnabled = enabled;
|
||||
mqttClient.disconnect();
|
||||
|
||||
if (!checkMqttHost(host, port))
|
||||
return false;
|
||||
|
||||
if (enabled) {
|
||||
Serial.println(F("Reconnecting to MQTT..."));
|
||||
setMqttServer(host, port);
|
||||
if (username.length() > 0) {
|
||||
mqttClient.setCredentials(
|
||||
retainCstr(username.c_str(), &retainedUsername),
|
||||
retainCstr(password.length() > 0 ? password.c_str() : nullptr, &retainedPassword));
|
||||
} else {
|
||||
mqttClient.setCredentials(retainCstr(nullptr, &retainedUsername), retainCstr(nullptr, &retainedPassword));
|
||||
}
|
||||
mqttClient.setClientId(retainCstr(clientId.c_str(), &retainedClientId));
|
||||
mqttClient.setKeepAlive(keepAlive);
|
||||
mqttClient.setCleanSession(cleanSession);
|
||||
mqttClient.setMaxTopicLength(maxTopicLength);
|
||||
mqttClient.connect();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool configureMqtt(JsonVariant& root) {
|
||||
configureMqtt(
|
||||
root["enabled"].as<bool>(),
|
||||
root["host"].as<String>(),
|
||||
root["port"].as<uint16_t>(),
|
||||
root["username"].as<String>(),
|
||||
root["password"].as<String>(),
|
||||
root["client_id"].as<String>(),
|
||||
root["keep_alive"].as<uint16_t>(),
|
||||
root["clean_session"].as<bool>(),
|
||||
root["max_topic_length"].as<uint16_t>()
|
||||
);
|
||||
}
|
||||
|
||||
void getDefaultMqttConf(JsonVariant& root) {
|
||||
root["enabled"] = FACTORY_MQTT_ENABLED;
|
||||
root["host"] = FACTORY_MQTT_HOST;
|
||||
root["port"] = FACTORY_MQTT_PORT;
|
||||
root["username"] = FACTORY_MQTT_USERNAME;
|
||||
root["password"] = FACTORY_MQTT_PASSWORD;
|
||||
root["client_id"] = formatSetting(FACTORY_MQTT_CLIENT_ID);
|
||||
root["keep_alive"] = FACTORY_MQTT_KEEP_ALIVE;
|
||||
root["clean_session"] = FACTORY_MQTT_CLEAN_SESSION;
|
||||
root["max_topic_length"] = FACTORY_MQTT_MAX_TOPIC_LENGTH;
|
||||
}
|
||||
|
||||
bool loadMqttConfig() {
|
||||
bool success = readJsonVariantFromFile(MQTT_SETTINGS_PATH, mqttConf);
|
||||
|
||||
if (!success)
|
||||
return false;
|
||||
}
|
||||
|
||||
void reconnectMQTTIfNeeded() {
|
||||
if (!mqttClient.connected()) {
|
||||
if (mqttConf.isNull())
|
||||
loadMqttConfig();
|
||||
|
||||
JsonVariant root = mqttConf.as<JsonVariant>();
|
||||
|
||||
if (!mqttConf.is<JsonVariant>())
|
||||
return;
|
||||
|
||||
bool mqttConfigured = configureMqtt(
|
||||
root["enabled"].as<bool>(),
|
||||
root["host"].as<String>(),
|
||||
root["port"].as<uint16_t>(),
|
||||
root["username"].as<String>(),
|
||||
root["password"].as<String>(),
|
||||
root["client_id"].as<String>(),
|
||||
root["keep_alive"].as<uint16_t>(),
|
||||
root["clean_session"].as<bool>(),
|
||||
root["max_topic_length"].as<uint16_t>()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void initMQTT() {
|
||||
mqttClient.onConnect(onMqttConnect);
|
||||
mqttClient.onDisconnect(onMqttDisconnect);
|
||||
mqttClient.onSubscribe(onMqttSubscribe);
|
||||
mqttClient.onUnsubscribe(onMqttUnsubscribe);
|
||||
//mqttClient.onMessage(onMqttMessage);
|
||||
//mqttClient.onPublish(onMqttPublish);
|
||||
mqttClient.setServer(MQTT_HOST, MQTT_PORT);
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <ETH.h>
|
||||
#include <HTTPClient.h>
|
||||
#include <AsyncMqttClient.h>
|
||||
|
||||
void connectToMqtt();
|
||||
void onMqttConnect(bool sessionPresent);
|
||||
void onMqttDisconnect(AsyncMqttClientDisconnectReason reason);
|
||||
void onMqttSubscribe(uint16_t packetId, uint8_t qos);
|
||||
void onMqttUnsubscribe(uint16_t packetId);
|
||||
void onMqttPublish(uint16_t packetId);
|
||||
void sendDataToMQTT(int flatNumber);
|
||||
void publishToMQTT(const char* topic, const char* message);
|
||||
void publishToMQTT(const char* topic, int message);
|
||||
void publishToMQTT(const char* topic, float message);
|
||||
void publishToMQTT(const char* topic, bool message);
|
||||
void initMQTT();
|
||||
void initMQTT();
|
||||
|
||||
AsyncMqttClient& getMqttClient();
|
||||
AsyncMqttClientDisconnectReason& getMqttDisconnectReason();
|
||||
bool getMqttConnected();
|
||||
bool getMqttEnabled();
|
||||
bool configureMqtt(
|
||||
bool enabled,
|
||||
String host,
|
||||
uint16_t port,
|
||||
String username,
|
||||
String password,
|
||||
String clientId,
|
||||
uint16_t keepAlive,
|
||||
bool cleanSession,
|
||||
uint16_t maxTopicLength
|
||||
);
|
||||
void getDefaultMqttConf(JsonVariant& root);
|
||||
bool configureMqtt(JsonVariant& root);
|
||||
void reconnectMQTTIfNeeded();
|
0
src/infra/system.cpp
Normal file
0
src/infra/system.cpp
Normal file
0
src/infra/system.h
Normal file
0
src/infra/system.h
Normal file
21
src/main.cpp
21
src/main.cpp
@ -22,10 +22,10 @@
|
||||
uint32_t lastMillis;
|
||||
uint64_t lastMicros;
|
||||
|
||||
bool eth_connected = false;
|
||||
|
||||
int data = 0;
|
||||
|
||||
bool flag = false;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
@ -44,6 +44,7 @@ void setup() {
|
||||
relayTurnOn();
|
||||
delay(2000);
|
||||
|
||||
//initStateMachine();
|
||||
initFileSystem();
|
||||
initEth();
|
||||
initMQTT();
|
||||
@ -59,11 +60,21 @@ void loop() {
|
||||
if (PRINT_RAW_SIGNAL_FLAG)
|
||||
printf("{}", data);
|
||||
|
||||
lastMillis = micros() + DATA_PERIOD;
|
||||
lastMicros = micros() + DATA_PERIOD;
|
||||
}
|
||||
|
||||
if (eth_connected) {
|
||||
if (lastMillis < millis()) {;
|
||||
if (true) {
|
||||
if (lastMillis < millis()) {
|
||||
if (getMqttEnabled() && !getMqttConnected()) {
|
||||
reconnectMQTTIfNeeded();
|
||||
}
|
||||
/*if (flag) {
|
||||
changeState(RECEIVING_DATA);
|
||||
flag = false;
|
||||
} else {
|
||||
changeState(CONNECTED);
|
||||
flag = true;
|
||||
}*/
|
||||
lastMillis = millis() + 3000;
|
||||
}
|
||||
}
|
||||
|
51
src/utils/settings.cpp
Normal file
51
src/utils/settings.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
#include "utils/settings.h"
|
||||
|
||||
#ifdef ESP32
|
||||
const String PLATFORM = "esp32";
|
||||
#elif defined(ESP8266)
|
||||
const String PLATFORM = "esp8266";
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Returns a new string after replacing each instance of the pattern with a value generated by calling the provided
|
||||
* callback.
|
||||
*/
|
||||
String replaceEach(String value, String pattern, String (*generateReplacement)()) {
|
||||
while (true) {
|
||||
int index = value.indexOf(pattern);
|
||||
if (index == -1) {
|
||||
break;
|
||||
}
|
||||
value = value.substring(0, index) + generateReplacement() + value.substring(index + pattern.length());
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a random number, encoded as a hex string.
|
||||
*/
|
||||
String getRandom() {
|
||||
return String(random(2147483647), HEX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the station's MAC address to create a unique id for each device.
|
||||
*/
|
||||
String getUniqueId() {
|
||||
uint8_t mac[6];
|
||||
#ifdef ESP32
|
||||
esp_read_mac(mac, ESP_MAC_WIFI_STA);
|
||||
#elif defined(ESP8266)
|
||||
wifi_get_macaddr(STATION_IF, mac);
|
||||
#endif
|
||||
char macStr[13] = {0};
|
||||
sprintf(macStr, "%02x%02x%02x%02x%02x%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
return String(macStr);
|
||||
}
|
||||
|
||||
String formatSetting(String value) {
|
||||
value = replaceEach(value, "#{random}", getRandom);
|
||||
value.replace("#{unique_id}", getUniqueId());
|
||||
value.replace("#{platform}", PLATFORM);
|
||||
return value;
|
||||
}
|
5
src/utils/settings.h
Normal file
5
src/utils/settings.h
Normal file
@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
String formatSetting(String value);
|
11
src/utils/utils.cpp
Normal file
11
src/utils/utils.cpp
Normal file
@ -0,0 +1,11 @@
|
||||
#include "utils/utils.h"
|
||||
|
||||
String requestDataToStr(uint8_t *data, size_t len) {
|
||||
String str = "";
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
str += (char)data[i];
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
5
src/utils/utils.h
Normal file
5
src/utils/utils.h
Normal file
@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
String requestDataToStr(uint8_t *data, size_t len);
|
Loading…
x
Reference in New Issue
Block a user