Fix multiple bugs and harden modb_orno3.c

- Fix NULL pointer dereference: move modbus_set_slave after ctx validation (ORNO)
- Fix InfluxDB line protocol: remove stray comma in voltage measurement
- Move InfluxDB token to env variable INFLUX_TOKEN with fallback to default
- Fix spike detection for negative power values using fabs()
- Read and validate HTTP response from InfluxDB after writes
- Replace all sprintf with snprintf to prevent buffer overflows
- Batch ORNO InfluxDB writes into single TCP connection (5→1)
- Fix non-portable absolute include path for modbus-rtu.h

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
ms
2026-02-14 19:32:04 +01:00
parent 886cecf523
commit aa31532d8c

View File

@@ -1,7 +1,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include </usr/include/modbus/modbus-rtu.h>
#include <modbus/modbus-rtu.h>
#include <errno.h>
#include <time.h>
#include <unistd.h>
@@ -62,7 +62,7 @@ typedef struct { float Freq; } s_frequency;
#define INFLUX_PORT 5086
#define INFLUX_ORG "sic" /* Zmień na swoją organizację */
#define INFLUX_BUCKET "energydb" /* Zmień na swój bucket */
#define INFLUX_TOKEN "BCIZ6kcCAVgpcwSfU0PBS7m0Zb6an93kuOtizbEtlXub-uaoYp4dmIQBQYaJCv8_KE4QYYZ08jxtpaZ3TUWP-Q==" /* Zmień na swój token */
#define INFLUX_TOKEN_DEFAULT "BCIZ6kcCAVgpcwSfU0PBS7m0Zb6an93kuOtizbEtlXub-uaoYp4dmIQBQYaJCv8_KE4QYYZ08jxtpaZ3TUWP-Q==" /* Fallback - preferuj zmienną INFLUX_TOKEN */
/* ============================================ */
/*
@@ -156,6 +156,7 @@ void mosq_log_callback(struct mosquitto *mosq, void *userdata, int level, const
}
}
const char *influx_token = NULL;
struct mosquitto *mosq = NULL;
void mqtt_setup()
{
@@ -224,7 +225,7 @@ int mqtt_send_U(float U1, float U2, float U3)
{
if (DISABLE_MQTT) return 0;
char buf[128];
sprintf(buf, "{\"U1\":%f,\"U2\":%f,\"U3\":%f}", U1, U2, U3);
snprintf(buf, sizeof(buf), "{\"U1\":%f,\"U2\":%f,\"U3\":%f}", U1, U2, U3);
return mosquitto_publish(mosq, NULL, "/energy/orno/U", strlen(buf), buf, 0, 0);
}
@@ -232,7 +233,7 @@ int mqtt_send_P(float P_Tot, float P1, float P2, float P3)
{
if (DISABLE_MQTT) return 0;
char buf[128];
sprintf(buf, "{\"P_Tot\":%f,\"P1\":%f,\"P2\":%f,\"P3\":%f}", P_Tot, P1, P2, P3);
snprintf(buf, sizeof(buf), "{\"P_Tot\":%f,\"P1\":%f,\"P2\":%f,\"P3\":%f}", P_Tot, P1, P2, P3);
return mosquitto_publish(mosq, NULL, "/energy/orno/P", strlen(buf), buf, 0, 0);
}
@@ -240,7 +241,7 @@ int mqtt_send_W(float W_Tot, float W1, float W2, float W3)
{
if (DISABLE_MQTT) return 0;
char buf[128];
sprintf(buf, "{\"W_Tot\":%f,\"W1\":%f,\"W2\":%f,\"W3\":%f}", W_Tot, W1, W2, W3);
snprintf(buf, sizeof(buf), "{\"W_Tot\":%f,\"W1\":%f,\"W2\":%f,\"W3\":%f}", W_Tot, W1, W2, W3);
return mosquitto_publish(mosq, NULL, "/energy/orno/W", strlen(buf), buf, 0, 0);
}
@@ -248,7 +249,7 @@ int mqtt_send_I(float I1, float I2, float I3)
{
if (DISABLE_MQTT) return 0;
char buf[128];
sprintf(buf, "{\"I1\":%f,\"I2\":%f,\"I3\":%f}", I1, I2, I3);
snprintf(buf, sizeof(buf), "{\"I1\":%f,\"I2\":%f,\"I3\":%f}", I1, I2, I3);
return mosquitto_publish(mosq, NULL, "/energy/orno/I", strlen(buf), buf, 0, 0);
}
@@ -256,7 +257,7 @@ int mqtt_send_Hz(float Hz)
{
if (DISABLE_MQTT) return 0;
char buf[64];
sprintf(buf, "%f", Hz);
snprintf(buf, sizeof(buf), "%f", Hz);
return mosquitto_publish(mosq, NULL, "/energy/orno/Hz", strlen(buf), buf, 0, 0);
}
@@ -300,7 +301,7 @@ int influx_send_post(char *data)
"Content-Length: %ld\r\n"
"Content-Type: text/plain; charset=utf-8\r\n"
"Connection: close\r\n\r\n",
INFLUX_ORG, INFLUX_BUCKET, INFLUX_HOST, INFLUX_PORT, INFLUX_TOKEN, strlen(data));
INFLUX_ORG, INFLUX_BUCKET, INFLUX_HOST, INFLUX_PORT, influx_token, strlen(data));
if (send(sock, header, strlen(header), 0) < 0) {
perror("INFLUX: Send header to InfluxDB failed");
@@ -314,13 +315,31 @@ int influx_send_post(char *data)
return -1;
}
/* Read HTTP response to check for errors */
char resp[512];
int resp_len = recv(sock, resp, sizeof(resp) - 1, 0);
if (resp_len > 0) {
resp[resp_len] = '\0';
/* Check HTTP status code (e.g. "HTTP/1.1 204") */
int http_status = 0;
if (sscanf(resp, "HTTP/%*d.%*d %d", &http_status) == 1) {
if (http_status < 200 || http_status >= 300) {
printf("INFLUX: ERROR: HTTP %d response from InfluxDB\n", http_status);
close(sock);
return -1;
}
}
} else if (resp_len < 0) {
printf("INFLUX: WARNING: No response from InfluxDB (timeout)\n");
}
close(sock);
return 0;
}
int influx_send_U(float U1, float U2, float U3) {
char line[256];
snprintf(line, sizeof(line), "orno,device=orno,pomiar=voltage, L1=%.2f,L2=%.2f,L3=%.2f", U1, U2, U3);
snprintf(line, sizeof(line), "orno,device=orno,pomiar=voltage L1=%.2f,L2=%.2f,L3=%.2f", U1, U2, U3);
return influx_send_post(line);
}
@@ -348,6 +367,41 @@ int influx_send_Hz(float Hz) {
return influx_send_post(line);
}
int influx_send_orno_batch(s_voltage *v, int v_ok, s_current *i, int i_ok,
s_power *p, int p_ok, s_energy *w, int w_ok,
s_frequency *f, int f_ok) {
if (DISABLE_INFLUX) return 0;
char batch[1024];
int offset = 0;
if (v_ok) {
offset += snprintf(batch + offset, sizeof(batch) - offset,
"orno,device=orno,pomiar=voltage L1=%.2f,L2=%.2f,L3=%.2f\n", v->U1, v->U2, v->U3);
}
if (i_ok) {
offset += snprintf(batch + offset, sizeof(batch) - offset,
"orno,device=orno,pomiar=current L1=%.2f,L2=%.2f,L3=%.2f\n", i->I1, i->I2, i->I3);
}
if (p_ok) {
offset += snprintf(batch + offset, sizeof(batch) - offset,
"orno,device=orno,pomiar=power total=%.3f,L1=%.3f,L2=%.3f,L3=%.3f\n", p->P_Tot, p->P1, p->P2, p->P3);
}
if (w_ok) {
offset += snprintf(batch + offset, sizeof(batch) - offset,
"orno,device=orno,pomiar=energy total=%.3f,L1=%.3f,L2=%.3f,L3=%.3f\n", w->W_Tot, w->W1, w->W2, w->W3);
}
if (f_ok) {
offset += snprintf(batch + offset, sizeof(batch) - offset,
"orno,device=orno,pomiar=frequency value=%.4f\n", f->Freq);
}
if (offset == 0) return 0;
/* Remove trailing newline */
if (offset > 0 && batch[offset - 1] == '\n') batch[offset - 1] = '\0';
return influx_send_post(batch);
}
int influx_send_SUN2K(t_mb_reg *reg_to_send, char *_str_buf) {
if (!_str_buf || strlen(_str_buf) == 0) return 0;
char line[256];
@@ -398,7 +452,7 @@ int mosq_test()
char *buf = malloc(64);
while (k-- > 0)
{
sprintf(buf, "i=%i", i++);
snprintf(buf, 64, "i=%i", i++);
int snd = mqtt_send("/testtopic", buf);
if (snd != 0)
printf("TEST: mqtt_send error=%i\n", snd);
@@ -408,7 +462,14 @@ int mosq_test()
int main(int argc, char *argv[])
{
/* Użyj wartości z #define */
/* Użyj wartości z #define, token z env lub fallback */
influx_token = getenv("INFLUX_TOKEN");
if (!influx_token || strlen(influx_token) == 0) {
influx_token = INFLUX_TOKEN_DEFAULT;
printf("CFG: INFLUX_TOKEN env not set, using default from code\n");
} else {
printf("CFG: INFLUX_TOKEN loaded from environment\n");
}
const char *USB_DEV = USB_DEV_DEFAULT;
int ORNO_SLAVE = ORNO_SLAVE_ADR;
int SUN2000_SLAVE = SUN2000_SLAVE_ADR;
@@ -455,13 +516,13 @@ int main(int argc, char *argv[])
{
//Create a new RTU context
modbus_t *ctx = modbus_new_rtu(USB_DEV, 9600, 'E', 8, 1);
//Set the Modbus address of the remote slave
modbus_set_slave(ctx, ORNO_SLAVE);
if (!ctx)
{
fprintf(stderr, "ORNO: Failed to create the context: %s\n", modbus_strerror(errno));
exit(1);
}
//Set the Modbus address of the remote slave
modbus_set_slave(ctx, ORNO_SLAVE);
if (modbus_connect(ctx) == -1)
{
@@ -616,7 +677,7 @@ int main(int argc, char *argv[])
}
int spike_P = 0;
if (prev_power.P_Tot != 0 && (current_power.P_Tot > prev_power.P_Tot * 1.8 || current_power.P_Tot < prev_power.P_Tot * 0.2)) spike_P = 1;
if (prev_power.P_Tot != 0 && (fabs(current_power.P_Tot - prev_power.P_Tot) > fabs(prev_power.P_Tot) * 0.8)) spike_P = 1;
if(spike_P) {
send_power = prev_power;
@@ -648,10 +709,12 @@ int main(int argc, char *argv[])
prev_freq = current_freq;
}
int valid_U = 0, valid_I = 0, valid_P = 0, valid_W = 0, valid_F = 0;
printf("ORNO: Voltages: L1=%.1f V, L2=%.1f V, L3=%.1f V\n", send_voltage.U1, send_voltage.U2, send_voltage.U3);
if (is_valid_float(send_voltage.U1, 150.0, 280.0) && is_valid_float(send_voltage.U2, 150.0, 280.0) && is_valid_float(send_voltage.U3, 150.0, 280.0)) {
mqtt_send_U(send_voltage.U1, send_voltage.U2, send_voltage.U3);
influx_send_U(send_voltage.U1, send_voltage.U2, send_voltage.U3);
valid_U = 1;
printf("ORNO: MQTT: Published voltages\n");
} else {
printf("ORNO: MQTT: Skipping voltages - invalid values\n");
@@ -660,7 +723,7 @@ int main(int argc, char *argv[])
printf("ORNO: Currents: L1=%.2f A, L2=%.2f A, L3=%.2f A\n", send_current.I1, send_current.I2, send_current.I3);
if (is_valid_float(send_current.I1, 0.0, 100.0) && is_valid_float(send_current.I2, 0.0, 100.0) && is_valid_float(send_current.I3, 0.0, 100.0)) {
mqtt_send_I(send_current.I1, send_current.I2, send_current.I3);
influx_send_I(send_current.I1, send_current.I2, send_current.I3);
valid_I = 1;
printf("ORNO: MQTT: Published currents\n");
} else {
printf("ORNO: MQTT: Skipping currents - invalid values\n");
@@ -669,7 +732,7 @@ int main(int argc, char *argv[])
printf("ORNO: Power: Total=%.3f W, L1=%.3f W, L2=%.3f W, L3=%.3f W\n", send_power.P_Tot, send_power.P1, send_power.P2, send_power.P3);
if (is_valid_float(send_power.P_Tot, -25000.0, 25000.0) && is_valid_float(send_power.P1, -10000.0, 10000.0) && is_valid_float(send_power.P2, -10000.0, 10000.0) && is_valid_float(send_power.P3, -10000.0, 10000.0)) {
mqtt_send_P(send_power.P_Tot, send_power.P1, send_power.P2, send_power.P3);
influx_send_P(send_power.P_Tot, send_power.P1, send_power.P2, send_power.P3);
valid_P = 1;
printf("ORNO: MQTT: Published power\n");
} else {
printf("ORNO: MQTT: Skipping power - invalid values\n");
@@ -678,7 +741,7 @@ int main(int argc, char *argv[])
printf("ORNO: Energy: Total=%.3f kWh, L1=%.3f kWh, L2=%.3f kWh, L3=%.3f kWh\n", send_energy.W_Tot, send_energy.W1, send_energy.W2, send_energy.W3);
if (is_valid_float(send_energy.W_Tot, 0.0, 1000000.0) && is_valid_float(send_energy.W1, 0.0, 1000000.0) && is_valid_float(send_energy.W2, 0.0, 1000000.0) && is_valid_float(send_energy.W3, 0.0, 1000000.0)) {
mqtt_send_W(send_energy.W_Tot, send_energy.W1, send_energy.W2, send_energy.W3);
influx_send_W(send_energy.W_Tot, send_energy.W1, send_energy.W2, send_energy.W3);
valid_W = 1;
printf("ORNO: MQTT: Published energy\n");
} else {
printf("ORNO: MQTT: Skipping energy - invalid values\n");
@@ -687,11 +750,17 @@ int main(int argc, char *argv[])
printf("ORNO: Frequency: %.4f Hz\n", send_freq.Freq);
if (is_valid_float(send_freq.Freq, 47.0, 53.0)) {
mqtt_send_Hz(send_freq.Freq);
influx_send_Hz(send_freq.Freq);
valid_F = 1;
printf("ORNO: MQTT: Published frequency\n");
} else {
printf("ORNO: MQTT: Skipping frequency - invalid value\n");
}
/* Send all ORNO data to InfluxDB in one batch (1 TCP connection instead of 5) */
influx_send_orno_batch(
&send_voltage, valid_U, &send_current, valid_I,
&send_power, valid_P, &send_energy, valid_W,
&send_freq, valid_F);
}
}
if (do_sun2k)