Skip to content

Commit 0b7d03d

Browse files
committed
v3.29
1 parent dc9896c commit 0b7d03d

File tree

9 files changed

+107
-43
lines changed

9 files changed

+107
-43
lines changed

Makefile

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,30 @@
11
CXX=g++
2+
FLAGS_MACOS=-O3 -std=c++17
3+
FLAGS_LINUX=-O3
4+
OS_NAME := $(shell uname -s)
5+
CXXFLAGS=
6+
7+
ifeq ($(OS_NAME), Linux)
8+
CXXFLAGS = $(FLAGS_LINUX)
9+
endif
10+
11+
ifeq ($(OS_NAME), Darwin)
12+
CXXFLAGS = $(FLAGS_MACOS)
13+
endif
14+
215
TARGET=rscp2mqtt
316

417
all: $(TARGET)
518

619
$(TARGET): clean
720
ifeq ($(WITH_INFLUXDB), yes)
8-
$(CXX) -O3 RscpMqttMain.cpp RscpProtocol.cpp AES.cpp SocketConnection.cpp -pthread -lmosquitto -lcurl -o $@ -DINFLUXDB
21+
$(CXX) $(CXXFLAGS) RscpMqttMain.cpp RscpProtocol.cpp AES.cpp SocketConnection.cpp -pthread -lmosquitto -lcurl -o $@ -DINFLUXDB
922
else
10-
$(CXX) -O3 RscpMqttMain.cpp RscpProtocol.cpp AES.cpp SocketConnection.cpp -pthread -lmosquitto -o $@
23+
$(CXX) $(CXXFLAGS) RscpMqttMain.cpp RscpProtocol.cpp AES.cpp SocketConnection.cpp -pthread -lmosquitto -o $@
1124
endif
1225

1326
clean:
1427
-rm $(TARGET)
28+
29+
.PHONY: all clean
30+

NEWTAGS.md

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,21 +91,24 @@ ADD_NEW_TOPIC=TAG_EMS_MAX_DC_POWER:TAG_EMS_PARAM_POWER_VALUE_L3:W:1:0:system/max
9191
### Configuration of New Set Topics
9292

9393
```
94-
ADD_NEW_SET_TOPIC=<container>:<tag>:<topic>:<regex>-<datatype<
94+
ADD_NEW_SET_TOPIC=<container>:<tag>:<index>:<topic>:<regex>#<datatype<
9595
# or
96-
ADD_NEW_SET_TOPIC=<container>:<tag>:<topic>:<true_regex>:<true_value>:<false_regex>:<false_value>-<datatype<
96+
ADD_NEW_SET_TOPIC=<container>:<tag>:<index>:<topic>:<true_regex>:<true_value>:<false_regex>:<false_value>#<datatype<
9797
```
98-
You can use "regex" to define a regular expression that checks the input payload, e.g. for permitted numbers.
98+
You can use "regex" to define a regular expression that checks the input payload, e.g. for permitted numbers. Don't use ":" or "#" in the regex!
9999

100100
To check boolean values use the fields "true_regex" and "false_regex" to check the input payload for true and false. "true_value" and "false_value" define the values that are to be sent to the home power station.
101101

102+
"index" can be the index of a wallbox. Set "0" if unknown.
103+
102104
Possible data types are "Bool", "Char8", "UChar8", "Int32", "UInt32" and "Float32".
103105

104106
See various examples in RscpMqttMapping.h
105107

106-
#### Example "Other set command for weather regulation"
108+
#### Examples
107109
```
108-
ADD_NEW_SET_TOPIC=TAG_EMS_REQ_SET_POWER_SETTINGS:TAG_EMS_WEATHER_REGULATED_CHARGE_ENABLED:set/weather:^true|on|1$:1:^false|off|0$:0-UChar8
110+
ADD_NEW_SET_TOPIC=TAG_EMS_REQ_SET_POWER_SETTINGS:TAG_EMS_WEATHER_REGULATED_CHARGE_ENABLED:0:set/weather:^true|on|1$:1:^false|off|0$:0#UChar8
111+
ADD_NEW_SET_TOPIC=TAG_WB_REQ_DATA:TAG_WB_REQ_SET_MIN_CHARGE_CURRENT:0:set/wallbox/min_current:^[0-9]{1,2}$#UChar8
109112
```
110113

111114
### One-time Execution
@@ -114,6 +117,7 @@ The program can be started that it executes only one entire interval.
114117
```
115118
./rscp2mqtt -1
116119
```
120+
117121
### Remarks
118122

119123
The procedure for integrating new tags is always trial and error. The structure of the tags is not standardized. There is no guarantee that you will get the expected values. Sometimes you receive multiple tags or tag structures in response to a single query. A look at the list of generated errors can be very helpful.

README.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
This software module connects a home power station from E3/DC to an MQTT broker.
1010

11-
It uses the RSCP interface of the device. The solution is based on the RSCP sample application provided by E3/DC and was developed and tested with a Raspberry Pi and a Linux PC (x86_64).
11+
It uses the RSCP interface of the device. The solution is based on the RSCP sample application provided by E3/DC and was developed and tested with a Raspberry Pi, a Linux PC (x86_64) and an Apple MacBook (x86_64).
1212

1313
The tool cyclically queries data from the home power station and publishes it to an MQTT broker using these [topics](TOPICS.md).
1414

@@ -54,7 +54,7 @@ Please also take a look at the [release notes](RELEASE.md).
5454

5555
## Docker
5656

57-
Instead of installing the package you can use a [Docker image](DOCKER.md).
57+
Instead of installing the package you can use a [Docker image](DOCKER.md) for Linux platforms (not MacOS).
5858

5959
## Prerequisites
6060

@@ -70,6 +70,11 @@ If you like to transfer data to InfluxDB install the libcurl library:
7070
sudo apt-get install curl libcurl4-openssl-dev
7171
```
7272

73+
On MacOS try
74+
```
75+
brew install mosquitto curl
76+
```
77+
7378
## Cloning the Repository
7479

7580
```
@@ -155,7 +160,7 @@ or to show the help page
155160
If everything works properly, you will see something like this:
156161

157162
```
158-
rscp2mqtt [3.28]
163+
rscp2mqtt [3.29]
159164
E3DC system >192.168.178.111:5033< user: >your E3DC user<
160165
MQTT broker >localhost:1883< qos = >0< retain = >✗< tls >✗< client id >✗< prefix >e3dc<
161166
Requesting PVI ✓ | PM (0) | DCB ✓ (1 battery string) | Wallbox ✗ | Interval 2 | Autorefresh ✓ | Raw data ✗ | Logging OFF

RELEASE.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
## Release Notes
22

3+
### Release v3.29 (04.08.2024)
4+
5+
Bug fixes:
6+
- Issue #85: Error in "New Set Topics"
7+
8+
Features:
9+
- Issue #84: Wallbox - min current
10+
- MacOS support
11+
312
### Release v3.28 (27.07.2024)
413

514
Bug fixes:

RscpMqttConfig.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ typedef struct _config_t {
6868
bool once;
6969
int interval;
7070
int log_level;
71-
bool save_memory;
7271
int battery_strings;
7372
bool pvi_requests;
7473
int pvi_tracker;

RscpMqttMain.cpp

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
#include <regex>
2222
#include <mutex>
2323

24-
#define RSCP2MQTT_VERSION "3.28"
24+
#define RSCP2MQTT_VERSION "3.29"
2525

2626
#define AES_KEY_SIZE 32
2727
#define AES_BLOCK_SIZE 32
@@ -69,7 +69,6 @@ static wb_t wb_stat;
6969
static int day, leap_day, year, curr_day, curr_year, battery_nr, pm_nr, wb_nr;
7070
static uint8_t period_change_nr = 0;
7171
static bool period_trigger = false;
72-
static bool history_init = true;
7372
static bool day_end = false;
7473
static bool new_day = false;
7574

@@ -108,7 +107,7 @@ void wsleep(int sec) {
108107
}
109108

110109
bool hasSpaces(char *s) {
111-
for (int i = 0; i < strlen(s); i++) {
110+
for (size_t i = 0; i < strlen(s); i++) {
112111
if (isspace(s[i])) return(true);
113112
}
114113
return(false);
@@ -159,7 +158,7 @@ uint8_t typeID(std::vector<RSCP_TAGS::rscp_types_t> & v, char *type) {
159158
return(0);
160159
}
161160

162-
char *errName(std::vector<RSCP_TAGS::rscp_err_codes_t> & v, int code) {
161+
char *errName(std::vector<RSCP_TAGS::rscp_err_codes_t> & v, uint32_t code) {
163162
char *unknown = NULL;
164163
for (std::vector<RSCP_TAGS::rscp_err_codes_t>::iterator it = v.begin(); it != v.end(); ++it) {
165164
if (!it->code) unknown = it->error;
@@ -316,7 +315,6 @@ int handleSetIdlePeriod(RscpProtocol *protocol, SRscpValue *rootContainer, char
316315

317316
void setTopicAttr() {
318317
for (std::vector<RSCP_MQTT::topic_store_t>::iterator i = RSCP_MQTT::TopicStore.begin(); i != RSCP_MQTT::TopicStore.end(); ++i) {
319-
if (i->topic == NULL) continue;
320318
switch (i->type) {
321319
case FORCED_TOPIC: {
322320
for (std::vector<RSCP_MQTT::cache_t>::iterator it = RSCP_MQTT::RscpMqttCache.begin(); it != RSCP_MQTT::RscpMqttCache.end(); ++it) {
@@ -1802,6 +1800,7 @@ void createRequest(SRscpFrameBuffer * frameBuffer) {
18021800
protocol.appendValue(&WBContainer, TAG_WB_REQ_PM_ENERGY_L1);
18031801
protocol.appendValue(&WBContainer, TAG_WB_REQ_PM_ENERGY_L2);
18041802
protocol.appendValue(&WBContainer, TAG_WB_REQ_PM_ENERGY_L3);
1803+
protocol.appendValue(&WBContainer, TAG_WB_REQ_MIN_CHARGE_CURRENT); // Issue #84
18051804
protocol.appendValue(&rootValue, WBContainer);
18061805
protocol.destroyValueData(WBContainer);
18071806
}
@@ -2017,7 +2016,7 @@ void createRequest(SRscpFrameBuffer * frameBuffer) {
20172016
if (wallboxExt[1] < 1) wallboxExt[1] = 1; else if (wallboxExt[1] > 32) wallboxExt[1] = 32; // max 32A
20182017
SRscpValue WBExtContainer;
20192018
protocol.createContainerValue(&WBExtContainer, TAG_WB_REQ_SET_EXTERN);
2020-
protocol.appendValue(&WBExtContainer, TAG_WB_EXTERN_DATA_LEN, sizeof(wallboxExt));
2019+
protocol.appendValue(&WBExtContainer, TAG_WB_EXTERN_DATA_LEN, (int)sizeof(wallboxExt));
20212020
protocol.appendValue(&WBExtContainer, TAG_WB_EXTERN_DATA, wallboxExt, sizeof(wallboxExt));
20222021
protocol.appendValue(&ReqContainer, WBExtContainer);
20232022
protocol.destroyValueData(WBExtContainer);
@@ -2101,7 +2100,7 @@ void createRequest(SRscpFrameBuffer * frameBuffer) {
21012100
void publishRaw(RscpProtocol *protocol, SRscpValue *response, char *topic) {
21022101
char *payload_new = (char *)malloc(PAYLOAD_SIZE * sizeof(char) + 1);
21032102
char *payload_old = readRawData(topic);
2104-
memset(payload_new, 0, sizeof(payload_new));
2103+
memset(payload_new, 0, PAYLOAD_SIZE);
21052104
preparePayload(protocol, response, &payload_new);
21062105
if (payload_old && payload_new && strcmp(payload_new, "") && strcmp(payload_old, payload_new)) {
21072106
publishImmediately(topic, payload_new, false);
@@ -2122,7 +2121,7 @@ void handleRaw(RscpProtocol *protocol, SRscpValue *response, uint32_t *cache, in
21222121
if (response->dataType == RSCP::eTypeError) return;
21232122

21242123
if (!l && (response->dataType != RSCP::eTypeContainer)) {
2125-
sprintf(topic, "raw/%s", tagName(RSCP_TAGS::RscpTagsOverview, response->tag));
2124+
snprintf(topic, TOPIC_SIZE, "raw/%s", tagName(RSCP_TAGS::RscpTagsOverview, response->tag));
21262125
if (!cfg.raw_topic_regex || std::regex_match(topic, std::regex(cfg.raw_topic_regex))) publishRaw(protocol, response, topic);
21272126
return;
21282127
}
@@ -2177,6 +2176,10 @@ int handleResponseValue(RscpProtocol *protocol, SRscpValue *response) {
21772176
RSCP_MQTT::date_t x;
21782177
uint32_t cache[RECURSION_MAX_LEVEL];
21792178

2179+
x.year = 0;
2180+
x.month = 0;
2181+
x.day = 0;
2182+
21802183
// check if any of the response has the error flag set and react accordingly
21812184
if (response->dataType == RSCP::eTypeError) {
21822185
// handle error for example access denied errors
@@ -2239,7 +2242,7 @@ int handleResponseValue(RscpProtocol *protocol, SRscpValue *response) {
22392242
} else {
22402243
switch (containerData[i].tag) {
22412244
case TAG_BAT_DCB_INFO: {
2242-
int dcb_nr;
2245+
int dcb_nr = 0;
22432246
std::vector<SRscpValue> container = protocol->getValueAsContainer(&containerData[i]);
22442247
for (size_t j = 0; j < container.size(); j++) {
22452248
if (container[j].tag == TAG_BAT_DCB_INDEX) {
@@ -2252,7 +2255,6 @@ int handleResponseValue(RscpProtocol *protocol, SRscpValue *response) {
22522255
break;
22532256
}
22542257
case TAG_BAT_DCB_COUNT: {
2255-
int dcb_nr;
22562258
cfg.bat_dcb_count[battery_nr] = protocol->getValueAsUChar8(&containerData[i]);
22572259
cfg.bat_dcb_start[battery_nr] = battery_nr?cfg.bat_dcb_count[battery_nr - 1]:0;
22582260
storeResponseValue(RSCP_MQTT::RscpMqttCache, protocol, &(containerData[i]), response->tag, 0);
@@ -2344,13 +2346,13 @@ int handleResponseValue(RscpProtocol *protocol, SRscpValue *response) {
23442346
case TAG_PVI_COS_PHI:
23452347
case TAG_PVI_VOLTAGE_MONITORING:
23462348
case TAG_PVI_FREQUENCY_UNDER_OVER: {
2347-
int tracker;
2349+
int tracker = 0;
23482350
std::vector<SRscpValue> container = protocol->getValueAsContainer(&containerData[i]);
23492351
for (size_t j = 0; j < container.size(); j++) {
23502352
if (container[j].tag == TAG_PVI_INDEX) {
23512353
tracker = protocol->getValueAsUInt16(&container[j]);
23522354
}
2353-
else if ((container[j].tag == TAG_PVI_VALUE)) {
2355+
else if (container[j].tag == TAG_PVI_VALUE) {
23542356
storeResponseValue(RSCP_MQTT::RscpMqttCache, protocol, &(container[j]), containerData[i].tag, tracker);
23552357
}
23562358
}
@@ -2400,7 +2402,13 @@ int handleResponseValue(RscpProtocol *protocol, SRscpValue *response) {
24002402
} else {
24012403
switch (containerData[i].tag) {
24022404
case TAG_EMS_IDLE_PERIOD: {
2403-
uint8_t period, type, active, starthour, startminute, endhour, endminute;
2405+
uint8_t period = 0;
2406+
uint8_t type = 0;
2407+
uint8_t active = 0;
2408+
uint8_t starthour = 0;
2409+
uint8_t startminute = 0;
2410+
uint8_t endhour = 0;
2411+
uint8_t endminute = 0;
24042412
period_trigger = false;
24052413
std::vector<SRscpValue> container = protocol->getValueAsContainer(&containerData[i]);
24062414
for (size_t j = 0; j < container.size(); j++) {
@@ -2518,7 +2526,7 @@ int handleResponseValue(RscpProtocol *protocol, SRscpValue *response) {
25182526
std::vector<SRscpValue> dbData = protocol->getValueAsContainer(&(historyData[i]));
25192527
for (size_t j = 0; j < dbData.size(); ++j) {
25202528
if (response->tag == TAG_DB_HISTORY_DATA_DAY) {
2521-
if (day >= 2) {
2529+
if ((day >= 2) && x.year) {
25222530
handleImmediately(protocol, &(dbData[j]), TAG_DB_HISTORY_DATA_DAY, x.year, x.month, x.day);
25232531
} else storeResponseValue(RSCP_MQTT::RscpMqttCache, protocol, &(dbData[j]), response->tag, day);
25242532
} else if (response->tag == TAG_DB_HISTORY_DATA_MONTH) {
@@ -2806,9 +2814,7 @@ static void mainLoop(void) {
28062814
if (countdown >= 0) {
28072815
countdown--;
28082816
if (countdown == 0) {
2809-
char topic[TOPIC_SIZE];
28102817
cleanupCache(RSCP_MQTT::RscpMqttCacheTempl);
2811-
if (cfg.save_memory) RSCP_TAGS::RscpTagsOverview.clear();
28122818
if (cfg.pvi_requests) pviStringNull(RSCP_MQTT::RscpMqttCache, cfg.pvi_tracker);
28132819
if (cfg.wallbox) wallboxDailyNull(RSCP_MQTT::RscpMqttCache, cfg.wb_number, true);
28142820
while (!RSCP_MQTT::mqttQ.empty()) {
@@ -2903,7 +2909,6 @@ int main(int argc, char *argv[]) {
29032909
for (uint8_t i = 0; i < MAX_WB_COUNT; i++) {
29042910
cfg.wb_indexes[i] = 0;
29052911
}
2906-
cfg.save_memory = false;
29072912
cfg.pm_number = 0;
29082913
cfg.wb_number = 0;
29092914
cfg.pm_extern = false;
@@ -3094,8 +3099,6 @@ int main(int argc, char *argv[]) {
30943099
cfg.auto_refresh = true;
30953100
else if ((strcasecmp(key, "RETAIN_FOR_SETUP") == 0) && (strcasecmp(value, "true") == 0))
30963101
cfg.store_setup = true;
3097-
else if ((strcasecmp(key, "SAVE_MEMORY") == 0) && (strcasecmp(value, "true") == 0))
3098-
cfg.save_memory = true;
30993102
else if ((strcasecmp(key, "USE_TRUE_FALSE") == 0) && (strcasecmp(value, "false") == 0)) {
31003103
strcpy(cfg.true_value, "1");
31013104
strcpy(cfg.false_value, "0");
@@ -3135,7 +3138,6 @@ int main(int argc, char *argv[]) {
31353138
} else logMessage(cfg.logfile, (char *)__FILE__, __LINE__, (char *)"key >%s< value >%s< not enough attributes.\n", key, value);
31363139
}
31373140
else if (strcasecmp(key, "ADD_NEW_TOPIC") == 0) {
3138-
int index = -1;
31393141
int divisor = 1;
31403142
int bit = 1;
31413143
char container[128];
@@ -3151,11 +3153,9 @@ int main(int argc, char *argv[]) {
31513153
} else logMessage(cfg.logfile, (char *)__FILE__, __LINE__, (char *)"key >%s< value >%s< not enough attributes.\n", key, value);
31523154
}
31533155
else if (strcasecmp(key, "ADD_NEW_SET_TOPIC") == 0) {
3154-
int index = -1;
3155-
int divisor = 1;
3156-
int bit = 1;
31573156
char container[128];
31583157
char tag[128];
3158+
int index = 0;
31593159
char topic[TOPIC_SIZE];
31603160
char regex_true[128];
31613161
char value_true[128];
@@ -3170,9 +3170,11 @@ int main(int argc, char *argv[]) {
31703170
memset(regex_false, 0, sizeof(regex_false));
31713171
memset(value_false, 0, sizeof(value_false));
31723172
memset(type, 0, sizeof(type));
3173-
if ((sscanf(value, "%127[^:]:%127[^:]:%127[^:]:%127[^:]:%127[^:]:%127[^:]:%127[^:]:%127[^:]", container, tag, topic, regex_true, value_true, regex_false, value_false, type) == 8)) {
3174-
if (isTag(RSCP_TAGS::RscpTagsOverview, container, false) && isTag(RSCP_TAGS::RscpTagsOverview, tag, false)) addSetTopic(tagID(RSCP_TAGS::RscpTagsOverview, container), tagID(RSCP_TAGS::RscpTagsOverview, tag), 0, topic, regex_true, value_true, regex_false, value_false, typeID(RSCP_TAGS::RscpTypeNames, type), true);
3175-
} else logMessage(cfg.logfile, (char *)__FILE__, __LINE__, (char *)"key >%s< value >%s< not enough attributes.\n", key, value);
3173+
if ((sscanf(value, "%127[^:#]:%127[^:#]:%d:%127[^:#]:%127[^:#]:%127[^:#]:%127[^:#]:%127[^:#]#%127[^:#]", container, tag, &index, topic, regex_true, value_true, regex_false, value_false, type) == 9) || (sscanf(value, "%127[^:#]:%127[^:#]:%d:%127[^:#]:%127[^:#]#%127[^:#]", container, tag, &index, topic, regex_true, type) == 6)) {
3174+
if (isTag(RSCP_TAGS::RscpTagsOverview, container, false) && isTag(RSCP_TAGS::RscpTagsOverview, tag, false) && (index >= 0)) addSetTopic(tagID(RSCP_TAGS::RscpTagsOverview, container), tagID(RSCP_TAGS::RscpTagsOverview, tag), index, topic, regex_true, value_true, regex_false, value_false, typeID(RSCP_TAGS::RscpTypeNames, type), true);
3175+
} else {
3176+
logMessage(cfg.logfile, (char *)__FILE__, __LINE__, (char *)"key >%s< value >%s< not enough attributes.\n", key, value);
3177+
}
31763178
}
31773179
}
31783180
}
@@ -3213,6 +3215,11 @@ int main(int argc, char *argv[]) {
32133215
addSetTopic(TAG_WB_REQ_DATA, TAG_WB_EXTERN_DATA, c, topic, (char *)"^true|on|1$", (char *)"1", (char *)"^false|off|0$", (char *)"0", RSCP::eTypeBool, false);
32143216
sprintf(topic, "set/wallbox/%d/max_current", c + 1);
32153217
addSetTopic(TAG_WB_REQ_DATA, TAG_WB_EXTERN_DATA, c, topic, (char *)"^[0-9]{1,2}$", (char *)"", (char *)"", (char *)"", RSCP::eTypeUChar8, false);
3218+
3219+
// Issue #84
3220+
sprintf(topic, "set/wallbox/%d/min_current", c + 1);
3221+
addSetTopic(TAG_WB_REQ_DATA, TAG_WB_REQ_SET_MIN_CHARGE_CURRENT, c, topic, (char *)"^[0-9]{1,2}$", (char *)"", (char *)"", (char *)"", RSCP::eTypeUChar8, false);
3222+
32163223
sprintf(topic, "set/wallbox/%d/number_phases", c + 1);
32173224
addSetTopic(TAG_WB_REQ_DATA, TAG_WB_REQ_SET_NUMBER_PHASES, c, topic, (char *)"^1|3$", (char *)"", (char *)"", (char *)"", RSCP::eTypeUChar8, true);
32183225
}

0 commit comments

Comments
 (0)