Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AC Charger über SMART PLUG via HTTP get einschalten #1330

Open
wants to merge 37 commits into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
a7fdf64
Changes to be committed:
Snoopy-HSS Oct 6, 2024
f96822f
Merge branch 'helgeerbe:development' into development
Snoopy-HSS Oct 6, 2024
2cfcbea
Merge branch 'helgeerbe:development' into development
Snoopy-HSS Oct 7, 2024
42da080
Changes to be committed:
Snoopy-HSS Oct 7, 2024
84013cd
Merge branch 'development' of https://github.com/Snoopy-HSS/OpenDTU-O…
Snoopy-HSS Oct 7, 2024
46ed857
Changes to be committed:
Snoopy-HSS Oct 14, 2024
f36ad51
Merge branch 'hoylabs:development' into development
Snoopy-HSS Oct 14, 2024
4a66ea0
Changes to be committed:
Snoopy-HSS Oct 19, 2024
2d5b999
Changes to be committed:
Snoopy-HSS Oct 19, 2024
4e1f201
Changes to be committed:
Snoopy-HSS Oct 19, 2024
b770213
Changes to be committed:
Snoopy-HSS Oct 19, 2024
9a58a08
Merge branch 'hoylabs:development' into development
Snoopy-HSS Oct 21, 2024
d78f6ec
Merge branch 'hoylabs:development' into development
Snoopy-HSS Oct 23, 2024
0a848ad
Merge branch 'development' into development
Snoopy-HSS Nov 11, 2024
9bc071c
Update AcChargerAdminView.vue
Snoopy-HSS Nov 11, 2024
f0be5c3
Update AcChargerAdminView.vue
Snoopy-HSS Nov 11, 2024
23009c4
Update AcChargerAdminView.vue
Snoopy-HSS Nov 11, 2024
b187ecc
Update AcChargerAdminView.vue
Snoopy-HSS Nov 11, 2024
adcc4ba
Update ShellyACPlug.cpp
Snoopy-HSS Nov 11, 2024
afe3238
Merge branch 'development' into development
Snoopy-HSS Nov 18, 2024
b191dcf
Changes to be committed:
Snoopy-HSS Nov 18, 2024
a31b24f
Merge branch 'hoylabs:development' into development
Snoopy-HSS Nov 19, 2024
b4aede6
POWERSTATE umgestellt auf eine CLASS Variable statt 2 Config Variablen.
Snoopy-HSS Nov 19, 2024
681d63c
Kleine Fehlerkorrektur
Snoopy-HSS Nov 20, 2024
2605412
Merge branch 'hoylabs:development' into development
Snoopy-HSS Nov 21, 2024
bd32581
Added Start at SoC config value
Snoopy-HSS Nov 25, 2024
bc86bf2
Merge branch 'hoylabs:development' into development
Snoopy-HSS Nov 25, 2024
5e4318d
Merge branch 'hoylabs:development' into development
Snoopy-HSS Nov 27, 2024
6016c39
Merge branch 'hoylabs:development' into development
Snoopy-HSS Nov 30, 2024
759da11
Merge branch 'development' into development
Snoopy-HSS Dec 1, 2024
fb72a3e
Merge branch 'hoylabs:development' into development
Snoopy-HSS Dec 3, 2024
2984777
Merge branch 'hoylabs:development' into development
Snoopy-HSS Dec 4, 2024
78e94ed
Merge branch 'hoylabs:development' into development
Snoopy-HSS Dec 5, 2024
13b19cb
Umgebaut um die URi für Power ON, Power OFF und STATS einzutragen.
Snoopy-HSS Dec 5, 2024
4d66e12
Added Parameter for finding power in output
Snoopy-HSS Dec 5, 2024
3faf7ed
Merge branch 'hoylabs:development' into development
Snoopy-HSS Dec 8, 2024
bfaf21e
Merge branch 'hoylabs:development' into development
Snoopy-HSS Dec 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions include/Configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,22 @@ struct CONFIG_T {
float Auto_Power_Target_Power_Consumption;
} Huawei;

struct {
bool Enabled;
bool VerboseLogging;
bool Auto_Power_BatterySoC_Limits_Enabled;
bool Emergency_Charge_Enabled;
uint8_t stop_batterysoc_threshold;
uint8_t start_batterysoc_threshold;
char url[1025];
char uri_on[1025];
char uri_off[1025];
char uri_stats[1025];
char uri_powerparam[256];
int32_t POWER_ON_threshold;
int32_t POWER_OFF_threshold;
} Shelly;


INVERTER_CONFIG_T Inverter[INV_MAX_COUNT];
char Dev_PinMapping[DEV_MAX_MAPPING_NAME_STRLEN + 1];
Expand Down
37 changes: 37 additions & 0 deletions include/ShellyACPlug.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <memory>
#include <condition_variable>
#include "HttpGetter.h"
#include "Configuration.h"
#include <TaskSchedulerDeclarations.h>
#include <stdint.h>
#include <atomic>
#include <array>
#include <variant>
#include <mutex>

class ShellyACPlugClass {
public:
bool init(Scheduler& scheduler);
void loop();
void PowerON();
void PowerOFF();
float _readpower;
private:
bool _initialized = false;
Task _loopTask;
const uint16_t _period = 2001;
float _acPower;
float _SoC;
bool _emergcharge;
bool send_http(String uri);
float read_http(String uri);
std::unique_ptr<HttpGetter> _HttpGetter;
bool powerstate = false;
bool verboselogging;
String uri_on;
String uri_off;
};

extern ShellyACPlugClass ShellyACPlug;
5 changes: 5 additions & 0 deletions include/WebApi.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,12 @@
#include "WebApi_ws_Huawei.h"
#include "WebApi_Huawei.h"
#include "WebApi_ws_battery.h"
#include "WebApi_Shelly.h"
#include "WebApi_ws_Shelly.h"
#include <ESPAsyncWebServer.h>
#include <TaskSchedulerDeclarations.h>


class WebApiClass {
public:
WebApiClass();
Expand Down Expand Up @@ -84,6 +87,8 @@ class WebApiClass {
WebApiHuaweiClass _webApiHuaweiClass;
WebApiWsHuaweiLiveClass _webApiWsHuaweiLive;
WebApiWsBatteryLiveClass _webApiWsBatteryLive;
WebApiShellyClass _webApiShellyClass;
WebApiWsShellyLiveClass _webApiWsShellyLive;
};

extern WebApiClass WebApi;
17 changes: 17 additions & 0 deletions include/WebApi_Shelly.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once

#include <ESPAsyncWebServer.h>
#include <TaskSchedulerDeclarations.h>
#include <AsyncJson.h>

class WebApiShellyClass {
public:
void init(AsyncWebServer& server, Scheduler& scheduler);
private:
void onStatus(AsyncWebServerRequest* request);
void onAdminGet(AsyncWebServerRequest* request);
void onAdminPost(AsyncWebServerRequest* request);

AsyncWebServer* _server;
};
31 changes: 31 additions & 0 deletions include/WebApi_ws_Shelly.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once

#include "ArduinoJson.h"
#include <ESPAsyncWebServer.h>
#include <TaskSchedulerDeclarations.h>
#include <mutex>

class WebApiWsShellyLiveClass {
public:
WebApiWsShellyLiveClass();
void init(AsyncWebServer& server, Scheduler& scheduler);
void reload();

private:
void generateCommonJsonResponse(JsonVariant& root);
void onLivedataStatus(AsyncWebServerRequest* request);
void onWebsocketEvent(AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len);

AsyncWebServer* _server;
AsyncWebSocket _ws;
AuthenticationMiddleware _simpleDigestAuth;

std::mutex _mutex;

Task _wsCleanupTask;
void wsCleanupTaskCb();

Task _sendDataTask;
void sendDataTaskCb();
};
2 changes: 1 addition & 1 deletion include/WebApi_ws_live.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class WebApiWsLiveClass {
uint32_t _lastPublishHuawei = 0;
uint32_t _lastPublishBattery = 0;
uint32_t _lastPublishPowerMeter = 0;

uint32_t _lastPublishShelly = 0;
uint32_t _lastPublishStats[INV_MAX_COUNT] = { 0 };

std::mutex _mutex;
Expand Down
11 changes: 11 additions & 0 deletions include/defaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,4 +169,15 @@
#define HUAWEI_AUTO_POWER_STOP_BATTERYSOC_THRESHOLD 95
#define HUAWEI_AUTO_POWER_TARGET_POWER_CONSUMPTION 0

#define SHELLY_ENABLED false
#define SHELLY_POWER_ON_THRESHOLD -500
#define SHELLY_POWER_OFF_THRESHOLD -100
#define SHELLY_STOP_BATTERYSOC_THRESHOLD 95
#define SHELLY_START_BATTERYSOC_THRESHOLD 90
#define SHELLY_IPADDRESS "http://192.168.2.100"
#define SHELLY_URION "/relay/0?turn=on"
#define SHELLY_URIOFF "/relay/0?turn=off"
#define SHELLY_URISTATS "/rpc/Switch.GetStatus?id=0"
#define SHELLY_URIPOWERPARAM "apower"

#define VERBOSE_LOGGING true
31 changes: 31 additions & 0 deletions src/Configuration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,21 @@ bool ConfigurationClass::write()
huawei["stop_batterysoc_threshold"] = config.Huawei.Auto_Power_Stop_BatterySoC_Threshold;
huawei["target_power_consumption"] = config.Huawei.Auto_Power_Target_Power_Consumption;

JsonObject shelly = doc["shelly"].to<JsonObject>();
shelly["enabled"] = config.Shelly.Enabled;
shelly["verbose_logging"] = config.Shelly.VerboseLogging;
shelly["auto_power_batterysoc_limits_enabled"]= config.Shelly.Auto_Power_BatterySoC_Limits_Enabled ;
shelly["emergency_charge_enabled"]= config.Shelly.Emergency_Charge_Enabled;
shelly["stop_batterysoc_threshold"] = config.Shelly.stop_batterysoc_threshold;
shelly["start_batterysoc_threshold"] = config.Shelly.start_batterysoc_threshold;
shelly["url"] = config.Shelly.url;
shelly["uri_on"] = config.Shelly.uri_on;
shelly["uri_off"] = config.Shelly.uri_off;
shelly["uri_stats"] = config.Shelly.uri_stats;
shelly["uri_powerparam"] = config.Shelly.uri_powerparam;
shelly["power_on_threshold"] = config.Shelly.POWER_ON_threshold;
shelly["power_off_threshold"] = config.Shelly.POWER_OFF_threshold;

if (!Utils::checkJsonAlloc(doc, __FUNCTION__, __LINE__)) {
return false;
}
Expand Down Expand Up @@ -690,6 +705,22 @@ bool ConfigurationClass::read()
config.Huawei.Auto_Power_Stop_BatterySoC_Threshold = huawei["stop_batterysoc_threshold"] | HUAWEI_AUTO_POWER_STOP_BATTERYSOC_THRESHOLD;
config.Huawei.Auto_Power_Target_Power_Consumption = huawei["target_power_consumption"] | HUAWEI_AUTO_POWER_TARGET_POWER_CONSUMPTION;

JsonObject shelly = doc["shelly"];
config.Shelly.Enabled = shelly["enabled"] | SHELLY_ENABLED;
config.Shelly.VerboseLogging = shelly["verbose_logging"] | VERBOSE_LOGGING;
config.Shelly.Auto_Power_BatterySoC_Limits_Enabled = shelly["auto_power_batterysoc_limits_enabled"] | false;
config.Shelly.Emergency_Charge_Enabled = shelly["emergency_charge_enabled"] | false;
config.Shelly.stop_batterysoc_threshold = shelly["stop_batterysoc_threshold"] | SHELLY_STOP_BATTERYSOC_THRESHOLD;
config.Shelly.start_batterysoc_threshold = shelly["start_batterysoc_threshold"] | SHELLY_START_BATTERYSOC_THRESHOLD;
strlcpy(config.Shelly.url, shelly["url"] | SHELLY_IPADDRESS, sizeof(config.Shelly.url));
strlcpy(config.Shelly.uri_on, shelly["uri_on"] | SHELLY_URION, sizeof(config.Shelly.uri_on));
strlcpy(config.Shelly.uri_off, shelly["uri_off"] | SHELLY_URIOFF, sizeof(config.Shelly.uri_off));
strlcpy(config.Shelly.uri_stats, shelly["uri_stats"] | SHELLY_URIOFF, sizeof(config.Shelly.uri_stats));
strlcpy(config.Shelly.uri_powerparam, shelly["uri_powerparam"] | SHELLY_URIOFF, sizeof(config.Shelly.uri_powerparam));
config.Shelly.POWER_ON_threshold = shelly["power_on_threshold"] | SHELLY_POWER_ON_THRESHOLD;
config.Shelly.POWER_OFF_threshold = shelly["power_off_threshold"] | SHELLY_POWER_OFF_THRESHOLD;


f.close();

// Check for default DTU serial
Expand Down
152 changes: 152 additions & 0 deletions src/ShellyACPlug.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "Utils.h"
#include "ShellyACPlug.h"
#include "MessageOutput.h"
#include <WiFiClientSecure.h>
#include <base64.h>
#include <ESPmDNS.h>
#include "Configuration.h"
#include "Datastore.h"
#include "PowerMeter.h"
#include "Battery.h"

ShellyACPlugClass ShellyACPlug;


bool ShellyACPlugClass::init(Scheduler& scheduler)
{
MessageOutput.printf("[ShellyACPlug::init] ShellyACPlug Initializing ...\r\n");
_initialized = true;
scheduler.addTask(_loopTask);
_loopTask.setCallback([this] { loop(); });
_loopTask.setIterations(TASK_FOREVER);
_loopTask.setInterval(_period);
_loopTask.enable();
return false;
}

void ShellyACPlugClass::loop()
{
const CONFIG_T& config = Configuration.get();
verboselogging=config.Shelly.VerboseLogging;
uri_on=config.Shelly.uri_on;
uri_off=config.Shelly.uri_off;
if (!config.Shelly.Enabled || !_initialized || !config.PowerMeter.Enabled ) {
return;
}
_loopTask.setInterval(_period);
_acPower = PowerMeter.getPowerTotal();
_SoC = Battery.getStats()->getSoC();
_emergcharge = Battery.getStats()->getImmediateChargingRequest();
_readpower = read_http(config.Shelly.uri_stats);
if (_readpower>0)
{
powerstate=true;
}
if ((_acPower < config.Shelly.POWER_ON_threshold && !powerstate && _SoC <= config.Shelly.start_batterysoc_threshold) || (_emergcharge && config.Shelly.Emergency_Charge_Enabled))
{
PowerON();
}
else if ((_acPower > config.Shelly.POWER_OFF_threshold && powerstate) || (_SoC >= config.Shelly.stop_batterysoc_threshold && powerstate))
{
PowerOFF();
}
if (verboselogging) {
MessageOutput.printf("[ShellyACPlug::loop] Power reported by the Smart Plug%f W\r\n", _acPower );
MessageOutput.printf("[ShellyACPlug::loop] State of the Smart Plug ON/OFF %d \r\n", powerstate );
MessageOutput.printf("[ShellyACPlug::loop] Current Battery SoC %f \r\n", _SoC);
MessageOutput.printf("[ShellyACPlug::loop] Current Power consumed by the household %f W\r\n", _readpower );
}
}

void ShellyACPlugClass::PowerON()
{
if (!send_http(uri_on))
{
return;
}
powerstate=true;
if (verboselogging) {
MessageOutput.print("[ShellyACPlug::PowerON] Power ON\r\n");
}
}

void ShellyACPlugClass::PowerOFF()
{
if (!send_http(uri_off))
{
return;
};
powerstate=false;
if (verboselogging) {
MessageOutput.print("[ShellyACPlug::PowerOFF] Power OFF\r\n");
}
}

bool ShellyACPlugClass::send_http(String uri)
{
const CONFIG_T& config = Configuration.get();
String url = config.Shelly.url;
url += uri;
HttpRequestConfig HttpRequest;
strlcpy(HttpRequest.Url, url.c_str(), sizeof(HttpRequest.Url));
HttpRequest.Timeout = 60;
_HttpGetter = std::make_unique<HttpGetter>(HttpRequest);
if (config.Shelly.VerboseLogging) {
MessageOutput.printf("[ShellyACPlug::send_http]] Start sending to URL: %s\r\n",url.c_str());
}
if (!_HttpGetter->init()) {
MessageOutput.printf("[ShellyACPlug::send_http]] ERROR INIT HttpGetter %s\r\n", _HttpGetter->getErrorText());
return false;
}
if (!_HttpGetter->performGetRequest()) {
MessageOutput.printf("[ShellyACPlug::send_http] ERROR GET HttpGetter %s\r\n", _HttpGetter->getErrorText());
return false;
}
_HttpGetter = nullptr;
return true;
}
float ShellyACPlugClass::read_http(String uri)
{
const CONFIG_T& config = Configuration.get();
String url = config.Shelly.url;
url += uri;
HttpRequestConfig HttpRequest;
JsonDocument jsonResponse;
strlcpy(HttpRequest.Url, url.c_str(), sizeof(HttpRequest.Url));
HttpRequest.Timeout = 60;
_HttpGetter = std::make_unique<HttpGetter>(HttpRequest);
if (config.Shelly.VerboseLogging) {
MessageOutput.printf("[ShellyACPlug::read_http] Start reading from URL: %s\r\n",url.c_str());
}
if (!_HttpGetter->init()) {
MessageOutput.printf("[ShellyACPlug::read_http] ERROR INIT HttpGetter %s\r\n", _HttpGetter->getErrorText());
return 0;
}
_HttpGetter->addHeader("Content-Type", "application/json");
_HttpGetter->addHeader("Accept", "application/json");
auto res = _HttpGetter->performGetRequest();
if (!res) {
MessageOutput.printf("[ShellyACPlug::read_http] ERROR GET HttpGetter %s\r\n", _HttpGetter->getErrorText());
return 0;
}
auto pStream = res.getStream();
if (!pStream) {
MessageOutput.printf("[ShellyACPlug::read_http] Programmer error: HTTP request yields no stream");
return 0;
}

const DeserializationError error = deserializeJson(jsonResponse, *pStream);
if (error) {
String msg("[ShellyACPlug::read_http] Unable to parse server response as JSON: ");
MessageOutput.printf((msg + error.c_str()).c_str());
return 0;
}
auto pathResolutionResult = Utils::getJsonValueByPath<float>(jsonResponse, config.Shelly.uri_powerparam);
if (!pathResolutionResult.second.isEmpty()) {
MessageOutput.printf("[ShellyACPlug::read_http] ERROR reading AC Power from Smart Plug %s\r\n",pathResolutionResult.second.c_str());
}

_HttpGetter = nullptr;
return pathResolutionResult.first;
}
4 changes: 3 additions & 1 deletion src/WebApi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ void WebApiClass::init(Scheduler& scheduler)
_webApiWsHuaweiLive.init(_server, scheduler);
_webApiHuaweiClass.init(_server, scheduler);
_webApiWsBatteryLive.init(_server, scheduler);

_webApiShellyClass.init(_server, scheduler);
_webApiWsShellyLive.init(_server, scheduler);
_server.begin();
}

Expand All @@ -55,6 +56,7 @@ void WebApiClass::reload()
_webApiWsBatteryLive.reload();
_webApiWsVedirectLive.reload();
_webApiWsHuaweiLive.reload();
_webApiWsShellyLive.reload();
}

bool WebApiClass::checkCredentials(AsyncWebServerRequest* request)
Expand Down
Loading