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:
107
modb_orno3.c
107
modb_orno3.c
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user