Skip to content

Commit

Permalink
Merge remote-tracking branch 'tbnobody/OpenDTU/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
helgeerbe committed Nov 26, 2022
2 parents 1fc0e76 + fe16a92 commit 2109520
Show file tree
Hide file tree
Showing 48 changed files with 418 additions and 90 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ This can be achieved by editing the 'platformio.ini' file and add/change one or
* Adjust the COM port in the file "platformio.ini" for your USB-serial-converter. It occurs twice:
* upload_port
* monitor_port
* Select the arrow button in the status bar (PlatformIO: Upload) to compile and upload the firmware. During the compilation, all required libraries are downloaded automatically.
* Select the arrow button in the blue bottom status bar (PlatformIO: Upload) to compile and upload the firmware. During the compilation, all required libraries are downloaded automatically.
* There are two videos showing these steps:
* [Git Clone and compilation](https://youtu.be/9cA_esv3zeA)
* [Full installation and compilation](https://youtu.be/xs6TqHn7QWM)
Expand Down Expand Up @@ -263,6 +263,7 @@ A documentation of the Web API can be found here: [Web-API Documentation](docs/W
* OpenDTU needs access to a working NTP server to get the current date & time.
* If your problem persists, check the [Issues on Github](https://github.com/tbnobody/OpenDTU/issues). Please inspect not only the open issues, also the closed issues contain useful information.
* Another source of information are the [Discussions](https://github.com/tbnobody/OpenDTU/discussions/)
* When flashing with VSCode Plattform.IO fails and also with ESPRESSIF tool a demo bin file cannot be flashed to the ESP32 with error message "A fatal error occurred: MD5 of file does not match data in flash!" than un-wire/unconnect ESP32 from the NRF24L01+ board. Try to flash again and rewire afterwards.

## Related Projects
- [Ahoy](https://github.com/grindylow/ahoy)
Expand Down
1 change: 1 addition & 0 deletions include/Configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ struct CONFIG_T {
bool Mqtt_Hass_Expire;

char Security_Password[WIFI_MAX_PASSWORD_STRLEN + 1];
bool Security_AllowReadonly;
};

class ConfigurationClass {
Expand Down
3 changes: 3 additions & 0 deletions include/WebApi.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "WebApi_firmware.h"
#include "WebApi_inverter.h"
#include "WebApi_limit.h"
#include "WebApi_maintenance.h"
#include "WebApi_mqtt.h"
#include "WebApi_network.h"
#include "WebApi_ntp.h"
Expand All @@ -28,6 +29,7 @@ class WebApiClass {
void loop();

static bool checkCredentials(AsyncWebServerRequest* request);
static bool checkCredentialsReadonly(AsyncWebServerRequest* request);

private:
AsyncWebServer _server;
Expand All @@ -40,6 +42,7 @@ class WebApiClass {
WebApiFirmwareClass _webApiFirmware;
WebApiInverterClass _webApiInverter;
WebApiLimitClass _webApiLimit;
WebApiMaintenanceClass _webApiMaintenance;
WebApiMqttClass _webApiMqtt;
WebApiNetworkClass _webApiNetwork;
WebApiNtpClass _webApiNtp;
Expand Down
15 changes: 15 additions & 0 deletions include/WebApi_maintenance.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once

#include <ESPAsyncWebServer.h>

class WebApiMaintenanceClass {
public:
void init(AsyncWebServer* server);
void loop();

private:
void onRebootPost(AsyncWebServerRequest* request);

AsyncWebServer* _server;
};
4 changes: 2 additions & 2 deletions include/WebApi_security.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ class WebApiSecurityClass {
void loop();

private:
void onPasswordGet(AsyncWebServerRequest* request);
void onPasswordPost(AsyncWebServerRequest* request);
void onSecurityGet(AsyncWebServerRequest* request);
void onSecurityPost(AsyncWebServerRequest* request);

void onAuthenticateGet(AsyncWebServerRequest* request);

Expand Down
1 change: 1 addition & 0 deletions include/defaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#define ACCESS_POINT_NAME "OpenDTU-"
#define ACCESS_POINT_PASSWORD "openDTU42"
#define AUTH_USERNAME "admin"
#define SECURITY_ALLOW_READONLY true

#define ADMIN_TIMEOUT 180
#define WIFI_RECONNECT_TIMEOUT 15
Expand Down
2 changes: 2 additions & 0 deletions src/Configuration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ bool ConfigurationClass::write()

JsonObject security = doc.createNestedObject("security");
security["password"] = config.Security_Password;
security["allow_readonly"] = config.Security_AllowReadonly;

JsonArray inverters = doc.createNestedArray("inverters");
for (uint8_t i = 0; i < INV_MAX_COUNT; i++) {
Expand Down Expand Up @@ -202,6 +203,7 @@ bool ConfigurationClass::read()

JsonObject security = doc["security"];
strlcpy(config.Security_Password, security["password"] | ACCESS_POINT_PASSWORD, sizeof(config.Security_Password));
config.Security_AllowReadonly = security["allow_readonly"] | SECURITY_ALLOW_READONLY;

JsonArray inverters = doc["inverters"];
for (uint8_t i = 0; i < INV_MAX_COUNT; i++) {
Expand Down
12 changes: 12 additions & 0 deletions src/WebApi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ void WebApiClass::init()
_webApiFirmware.init(&_server);
_webApiInverter.init(&_server);
_webApiLimit.init(&_server);
_webApiMaintenance.init(&_server);
_webApiMqtt.init(&_server);
_webApiNetwork.init(&_server);
_webApiNtp.init(&_server);
Expand All @@ -49,6 +50,7 @@ void WebApiClass::loop()
_webApiFirmware.loop();
_webApiInverter.loop();
_webApiLimit.loop();
_webApiMaintenance.loop();
_webApiMqtt.loop();
_webApiNetwork.loop();
_webApiNtp.loop();
Expand Down Expand Up @@ -79,4 +81,14 @@ bool WebApiClass::checkCredentials(AsyncWebServerRequest* request)
return false;
}

bool WebApiClass::checkCredentialsReadonly(AsyncWebServerRequest* request)
{
CONFIG_T& config = Configuration.get();
if (config.Security_AllowReadonly) {
return true;
} else {
return checkCredentials(request);
}
}

WebApiClass WebApi;
5 changes: 5 additions & 0 deletions src/WebApi_devinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "ArduinoJson.h"
#include "AsyncJson.h"
#include "Hoymiles.h"
#include "WebApi.h"
#include <ctime>

void WebApiDevInfoClass::init(AsyncWebServer* server)
Expand All @@ -23,6 +24,10 @@ void WebApiDevInfoClass::loop()

void WebApiDevInfoClass::onDevInfoStatus(AsyncWebServerRequest* request)
{
if (!WebApi.checkCredentialsReadonly(request)) {
return;
}

AsyncJsonResponse* response = new AsyncJsonResponse();
JsonObject root = response->getRoot();

Expand Down
5 changes: 5 additions & 0 deletions src/WebApi_eventlog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "ArduinoJson.h"
#include "AsyncJson.h"
#include "Hoymiles.h"
#include "WebApi.h"

void WebApiEventlogClass::init(AsyncWebServer* server)
{
Expand All @@ -22,6 +23,10 @@ void WebApiEventlogClass::loop()

void WebApiEventlogClass::onEventlogStatus(AsyncWebServerRequest* request)
{
if (!WebApi.checkCredentialsReadonly(request)) {
return;
}

AsyncJsonResponse* response = new AsyncJsonResponse(false, 2048);
JsonObject root = response->getRoot();

Expand Down
4 changes: 4 additions & 0 deletions src/WebApi_limit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ void WebApiLimitClass::loop()

void WebApiLimitClass::onLimitStatus(AsyncWebServerRequest* request)
{
if (!WebApi.checkCredentialsReadonly(request)) {
return;
}

AsyncJsonResponse* response = new AsyncJsonResponse();
JsonObject root = response->getRoot();

Expand Down
82 changes: 82 additions & 0 deletions src/WebApi_maintenance.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2022 Thomas Basler and others
*/

#include "WebApi_maintenance.h"
#include "AsyncJson.h"
#include "WebApi.h"

void WebApiMaintenanceClass::init(AsyncWebServer* server)
{
using std::placeholders::_1;

_server = server;

_server->on("/api/maintenance/reboot", HTTP_POST, std::bind(&WebApiMaintenanceClass::onRebootPost, this, _1));
}

void WebApiMaintenanceClass::loop()
{
}

void WebApiMaintenanceClass::onRebootPost(AsyncWebServerRequest* request)
{
if (!WebApi.checkCredentials(request)) {
return;
}

AsyncJsonResponse* response = new AsyncJsonResponse(false, MQTT_JSON_DOC_SIZE);
JsonObject retMsg = response->getRoot();
retMsg[F("type")] = F("warning");

if (!request->hasParam("data", true)) {
retMsg[F("message")] = F("No values found!");
response->setLength();
request->send(response);
return;
}

String json = request->getParam("data", true)->value();

if (json.length() > MQTT_JSON_DOC_SIZE) {
retMsg[F("message")] = F("Data too large!");
response->setLength();
request->send(response);
return;
}

DynamicJsonDocument root(MQTT_JSON_DOC_SIZE);
DeserializationError error = deserializeJson(root, json);

if (error) {
retMsg[F("message")] = F("Failed to parse data!");
response->setLength();
request->send(response);
return;
}

if (!(root.containsKey("reboot"))) {
retMsg[F("message")] = F("Values are missing!");
response->setLength();
request->send(response);
return;
}

if (root[F("reboot")].as<bool>()) {
retMsg[F("type")] = F("success");
retMsg[F("message")] = F("Reboot triggered!");

response->setLength();
request->send(response);
yield();
delay(1000);
yield();
ESP.restart();
} else {
retMsg[F("message")] = F("Reboot cancled!");

response->setLength();
request->send(response);
}
}
4 changes: 4 additions & 0 deletions src/WebApi_mqtt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ void WebApiMqttClass::loop()

void WebApiMqttClass::onMqttStatus(AsyncWebServerRequest* request)
{
if (!WebApi.checkCredentialsReadonly(request)) {
return;
}

AsyncJsonResponse* response = new AsyncJsonResponse(false, MQTT_JSON_DOC_SIZE);
JsonObject root = response->getRoot();
const CONFIG_T& config = Configuration.get();
Expand Down
4 changes: 4 additions & 0 deletions src/WebApi_network.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ void WebApiNetworkClass::loop()

void WebApiNetworkClass::onNetworkStatus(AsyncWebServerRequest* request)
{
if (!WebApi.checkCredentialsReadonly(request)) {
return;
}

AsyncJsonResponse* response = new AsyncJsonResponse();
JsonObject root = response->getRoot();

Expand Down
4 changes: 4 additions & 0 deletions src/WebApi_ntp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ void WebApiNtpClass::loop()

void WebApiNtpClass::onNtpStatus(AsyncWebServerRequest* request)
{
if (!WebApi.checkCredentialsReadonly(request)) {
return;
}

AsyncJsonResponse* response = new AsyncJsonResponse();
JsonObject root = response->getRoot();
const CONFIG_T& config = Configuration.get();
Expand Down
4 changes: 4 additions & 0 deletions src/WebApi_power.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ void WebApiPowerClass::loop()

void WebApiPowerClass::onPowerStatus(AsyncWebServerRequest* request)
{
if (!WebApi.checkCredentialsReadonly(request)) {
return;
}

AsyncJsonResponse* response = new AsyncJsonResponse();
JsonObject root = response->getRoot();

Expand Down
13 changes: 8 additions & 5 deletions src/WebApi_security.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,16 @@ void WebApiSecurityClass::init(AsyncWebServer* server)

_server = server;

_server->on("/api/security/password", HTTP_GET, std::bind(&WebApiSecurityClass::onPasswordGet, this, _1));
_server->on("/api/security/password", HTTP_POST, std::bind(&WebApiSecurityClass::onPasswordPost, this, _1));
_server->on("/api/security/config", HTTP_GET, std::bind(&WebApiSecurityClass::onSecurityGet, this, _1));
_server->on("/api/security/config", HTTP_POST, std::bind(&WebApiSecurityClass::onSecurityPost, this, _1));
_server->on("/api/security/authenticate", HTTP_GET, std::bind(&WebApiSecurityClass::onAuthenticateGet, this, _1));
}

void WebApiSecurityClass::loop()
{
}

void WebApiSecurityClass::onPasswordGet(AsyncWebServerRequest* request)
void WebApiSecurityClass::onSecurityGet(AsyncWebServerRequest* request)
{
if (!WebApi.checkCredentials(request)) {
return;
Expand All @@ -35,12 +35,13 @@ void WebApiSecurityClass::onPasswordGet(AsyncWebServerRequest* request)
const CONFIG_T& config = Configuration.get();

root[F("password")] = config.Security_Password;
root[F("allow_readonly")] = config.Security_AllowReadonly;

response->setLength();
request->send(response);
}

void WebApiSecurityClass::onPasswordPost(AsyncWebServerRequest* request)
void WebApiSecurityClass::onSecurityPost(AsyncWebServerRequest* request)
{
if (!WebApi.checkCredentials(request)) {
return;
Expand Down Expand Up @@ -76,7 +77,8 @@ void WebApiSecurityClass::onPasswordPost(AsyncWebServerRequest* request)
return;
}

if (!root.containsKey("password")) {
if (!root.containsKey("password")
&& root.containsKey("allow_readonly")) {
retMsg[F("message")] = F("Values are missing!");
response->setLength();
request->send(response);
Expand All @@ -92,6 +94,7 @@ void WebApiSecurityClass::onPasswordPost(AsyncWebServerRequest* request)

CONFIG_T& config = Configuration.get();
strlcpy(config.Security_Password, root[F("password")].as<String>().c_str(), sizeof(config.Security_Password));
config.Security_AllowReadonly = root[F("allow_readonly")].as<bool>();
Configuration.write();

retMsg[F("type")] = F("success");
Expand Down
5 changes: 5 additions & 0 deletions src/WebApi_sysstatus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "AsyncJson.h"
#include "Configuration.h"
#include "NetworkSettings.h"
#include "WebApi.h"
#include <Hoymiles.h>
#include <LittleFS.h>
#include <ResetReason.h>
Expand All @@ -30,6 +31,10 @@ void WebApiSysstatusClass::loop()

void WebApiSysstatusClass::onSystemStatus(AsyncWebServerRequest* request)
{
if (!WebApi.checkCredentialsReadonly(request)) {
return;
}

AsyncJsonResponse* response = new AsyncJsonResponse();
JsonObject root = response->getRoot();

Expand Down
4 changes: 4 additions & 0 deletions src/WebApi_vedirect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ void WebApiVedirectClass::loop()

void WebApiVedirectClass::onVedirectStatus(AsyncWebServerRequest* request)
{
if (!WebApi.checkCredentialsReadonly(request)) {
return;
}

AsyncJsonResponse* response = new AsyncJsonResponse();
JsonObject root = response->getRoot();
const CONFIG_T& config = Configuration.get();
Expand Down
Loading

0 comments on commit 2109520

Please sign in to comment.