dodatkowe modyfikacje dla zapobieżenia zarowym odczytow

This commit is contained in:
ms
2026-02-08 21:17:40 +01:00
parent 46dcd48309
commit cec575c435
4 changed files with 210 additions and 173 deletions

View File

@@ -1 +1,4 @@
gcc -g -I /usr/include/modbus modb_orno3.c -lmosquitto -lmodbus -o modborno3 gcc -g -I /usr/include/modbus modb_orno3.c -lmosquitto -lmodbus -o modborno3
cp modborno3 /home/ms/bin/modborno3
chmod +x /home/ms/bin/modborno3

View File

@@ -12,6 +12,15 @@
#include <netinet/in.h> #include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
/* ============================================ */
/* STRUCTS FOR MEASUREMENTS */
/* ============================================ */
typedef struct { float U1, U2, U3; } s_voltage;
typedef struct { float I1, I2, I3; } s_current;
typedef struct { float P_Tot, P1, P2, P3; } s_power;
typedef struct { float W_Tot, W1, W2, W3; } s_energy;
typedef struct { float Freq; } s_frequency;
/* ============================================ */ /* ============================================ */
/* KONFIGURACJA PROGRAMU - EDYTUJ TU */ /* KONFIGURACJA PROGRAMU - EDYTUJ TU */
/* ============================================ */ /* ============================================ */
@@ -406,6 +415,13 @@ int main(int argc, char *argv[])
int do_orno = READ_ORNO; int do_orno = READ_ORNO;
int do_sun2k = READ_SUN2K; int do_sun2k = READ_SUN2K;
s_voltage prev_voltage = {0}, current_voltage = {0};
s_current prev_current = {0}, current_current = {0};
s_power prev_power = {0}, current_power = {0};
s_energy prev_energy = {0}, current_energy = {0};
s_frequency prev_freq = {0}, current_freq = {0};
int first_run = 1;
float voltage_buffer_L1[VOLTAGE_BUFFER_SIZE] = {0}; float voltage_buffer_L1[VOLTAGE_BUFFER_SIZE] = {0};
float voltage_buffer_L2[VOLTAGE_BUFFER_SIZE] = {0}; float voltage_buffer_L2[VOLTAGE_BUFFER_SIZE] = {0};
float voltage_buffer_L3[VOLTAGE_BUFFER_SIZE] = {0}; float voltage_buffer_L3[VOLTAGE_BUFFER_SIZE] = {0};
@@ -437,10 +453,9 @@ int main(int argc, char *argv[])
{ {
if (do_orno) if (do_orno)
{ {
//Create a new RTU context with proper serial parameters (in this example, //Create a new RTU context
//device name /dev/ttyS0, baud rate 9600, no parity bit, 8 data bits, 1 stop bit)
modbus_t *ctx = modbus_new_rtu(USB_DEV, 9600, 'E', 8, 1); modbus_t *ctx = modbus_new_rtu(USB_DEV, 9600, 'E', 8, 1);
//Set the Modbus address of the remote slave (to 2) //Set the Modbus address of the remote slave
modbus_set_slave(ctx, ORNO_SLAVE); modbus_set_slave(ctx, ORNO_SLAVE);
if (!ctx) if (!ctx)
{ {
@@ -455,210 +470,229 @@ int main(int argc, char *argv[])
exit(1); exit(1);
} }
/* Enable libmodbus debug to print raw frames */
/* modbus_set_debug(ctx, TRUE); */ /* Disabled - causes timing issues */
/* Configure RTS delay and timeouts from #define */
modbus_rtu_set_rts_delay(ctx, ORNO_RTS_DELAY); modbus_rtu_set_rts_delay(ctx, ORNO_RTS_DELAY);
modbus_set_response_timeout(ctx, 0, 900000); /* 0.9s */ modbus_set_response_timeout(ctx, 0, 900000); /* 0.9s */
modbus_set_byte_timeout(ctx, 0, ORNO_BYTE_TIMEOUT); modbus_set_byte_timeout(ctx, 0, ORNO_BYTE_TIMEOUT);
/* Display current configuration */ printf("ORNO: RTS Delay and Timeouts configured.\n");
int rts_delay = modbus_rtu_get_rts_delay(ctx);
uint32_t response_timeout_sec, response_timeout_usec;
uint32_t byte_timeout_sec, byte_timeout_usec;
modbus_get_response_timeout(ctx, &response_timeout_sec, &response_timeout_usec);
modbus_get_byte_timeout(ctx, &byte_timeout_sec, &byte_timeout_usec);
printf("ORNO: RTS Delay %u us\n", rts_delay);
printf("ORNO: Response Timeout %u,%06u s\n", response_timeout_sec, response_timeout_usec);
printf("ORNO: Byte Timeout %u,%06u s\n", byte_timeout_sec, byte_timeout_usec);
uint16_t reg[32]; // will store read registers values uint16_t reg[32];
uint16_t reg2[2]; // will store read registers values int num;
float d = 0.0;
int num = 0; // ---- READ ALL ORNO VALUES ----
int proba = 0;
float U1, U2, U3; // VOLTAGES
float I1, I2, I3; num = modbus_read_timed(ctx, 0xe, 6, reg);
float P_Tot, P1, P2, P3; if (num == 6) {
float W_Tot, W1, W2, W3; current_voltage.U1 = modbus_get_float_abcd(&reg[0]);
float Freq; current_voltage.U2 = modbus_get_float_abcd(&reg[2]);
current_voltage.U3 = modbus_get_float_abcd(&reg[4]);
long l = 0; } else {
printf("ORNO: Failed to read voltages: %s\n", modbus_strerror(errno));
/* Flush serial buffer and wait for device to be ready */ current_voltage = prev_voltage; // On error, use previous values
modbus_flush(ctx);
usleep(100000); /* 100ms delay before first read */
memset((char *)reg, 0, sizeof(reg));
//NAPIECIA
num = modbus_read_timed(ctx, 0xe, 6, reg); // ORNO
// num = modbus_read_registers(ctx, 32072, 2, reg); // SUN2000
if (num != 6)
{ // number of read registers is not the one expected
printf("ORNO: %x \t\n", 0xe);
printf("ORNO: Failed to read: %s\n", modbus_strerror(errno));
} }
else usleep(100000);
{
U1 = modbus_get_float_abcd(&reg[0]);
U2 = modbus_get_float_abcd(&reg[2]);
U3 = modbus_get_float_abcd(&reg[4]);
printf("ORNO: Voltages: L1=%.1f V, L2=%.1f V, L3=%.1f V\n", U1, U2, U3);
// Add to circular buffer // CURRENTS
voltage_buffer_L1[voltage_buffer_index] = U1; num = modbus_read_timed(ctx, 0x16, 6, reg);
voltage_buffer_L2[voltage_buffer_index] = U2; if (num == 6) {
voltage_buffer_L3[voltage_buffer_index] = U3; current_current.I1 = modbus_get_float_abcd(&reg[0]);
voltage_buffer_index = (voltage_buffer_index + 1) % VOLTAGE_BUFFER_SIZE; current_current.I2 = modbus_get_float_abcd(&reg[2]);
if (voltage_buffer_items < VOLTAGE_BUFFER_SIZE) { current_current.I3 = modbus_get_float_abcd(&reg[4]);
voltage_buffer_items++; } else {
printf("ORNO: Failed to read currents: %s\n", modbus_strerror(errno));
current_current = prev_current;
}
usleep(100000);
// POWER
num = modbus_read_timed(ctx, 0x1c, 8, reg);
if (num == 8) {
current_power.P_Tot = modbus_get_float_abcd(&reg[0]);
current_power.P1 = modbus_get_float_abcd(&reg[2]);
current_power.P2 = modbus_get_float_abcd(&reg[4]);
current_power.P3 = modbus_get_float_abcd(&reg[6]);
} else {
printf("ORNO: Failed to read power: %s\n", modbus_strerror(errno));
current_power = prev_power;
}
usleep(100000);
// ENERGY
num = modbus_read_timed(ctx, 0x100, 8, reg);
if (num == 8) {
current_energy.W_Tot = modbus_get_float_abcd(&reg[0]);
current_energy.W1 = modbus_get_float_abcd(&reg[2]);
current_energy.W2 = modbus_get_float_abcd(&reg[4]);
current_energy.W3 = modbus_get_float_abcd(&reg[6]);
} else {
printf("ORNO: Failed to read energy: %s\n", modbus_strerror(errno));
current_energy = prev_energy;
}
usleep(10000);
// FREQUENCY
num = modbus_read_timed(ctx, 0x14, 2, reg);
if (num == 2) {
current_freq.Freq = modbus_get_float_abcd(&reg[0]);
} else {
printf("ORNO: Failed to read frequency: %s\n", modbus_strerror(errno));
current_freq = prev_freq;
}
modbus_close(ctx);
modbus_free(ctx);
// --- VOLTAGE FLUCTUATION DETECTION (uses fresh, unfiltered values) ---
voltage_buffer_L1[voltage_buffer_index] = current_voltage.U1;
voltage_buffer_L2[voltage_buffer_index] = current_voltage.U2;
voltage_buffer_L3[voltage_buffer_index] = current_voltage.U3;
voltage_buffer_index = (voltage_buffer_index + 1) % VOLTAGE_BUFFER_SIZE;
if (voltage_buffer_items < VOLTAGE_BUFFER_SIZE) {
voltage_buffer_items++;
}
float avg_L1 = 0, avg_L2 = 0, avg_L3 = 0;
for (int i = 0; i < voltage_buffer_items; i++) {
avg_L1 += voltage_buffer_L1[i];
avg_L2 += voltage_buffer_L2[i];
avg_L3 += voltage_buffer_L3[i];
}
avg_L1 /= voltage_buffer_items;
avg_L2 /= voltage_buffer_items;
avg_L3 /= voltage_buffer_items;
if (fabs(current_voltage.U1 - avg_L1) > avg_L1 * VOLTAGE_FLUCTUATION_THRESHOLD ||
fabs(current_voltage.U2 - avg_L2) > avg_L2 * VOLTAGE_FLUCTUATION_THRESHOLD ||
fabs(current_voltage.U3 - avg_L3) > avg_L3 * VOLTAGE_FLUCTUATION_THRESHOLD) {
printf("ORNO: Voltage fluctuation detected! Switching to high frequency polling for %d seconds.\n", HIGH_FREQ_MODE_DURATION);
mqtt_send("fluct/start", "on");
influx_send_post("orno,device=orno,highfluct=start value=true");
high_frequency_mode_end_time = time(NULL) + HIGH_FREQ_MODE_DURATION;
}
// --- DATA VALIDATION AND SENDING ---
if (first_run) {
prev_voltage = current_voltage;
prev_current = current_current;
prev_power = current_power;
prev_energy = current_energy;
prev_freq = current_freq;
first_run = 0;
printf("ORNO: First run, buffering initial measurements.\n");
} else {
s_voltage send_voltage;
s_current send_current;
s_power send_power;
s_energy send_energy;
s_frequency send_freq;
int spike_U = 0;
if (prev_voltage.U1 != 0 && (current_voltage.U1 > prev_voltage.U1 * 1.8 || current_voltage.U1 < prev_voltage.U1 * 0.2)) spike_U = 1;
if (prev_voltage.U2 != 0 && (current_voltage.U2 > prev_voltage.U2 * 1.8 || current_voltage.U2 < prev_voltage.U2 * 0.2)) spike_U = 1;
if (prev_voltage.U3 != 0 && (current_voltage.U3 > prev_voltage.U3 * 1.8 || current_voltage.U3 < prev_voltage.U3 * 0.2)) spike_U = 1;
if(spike_U) {
send_voltage = prev_voltage;
printf("ORNO: Voltage spike detected. Sending previous values.\n");
} else {
send_voltage = current_voltage;
prev_voltage = current_voltage;
} }
float avg_L1 = 0, avg_L2 = 0, avg_L3 = 0; int spike_I = 0;
for (int i = 0; i < voltage_buffer_items; i++) { if (prev_current.I1 != 0 && (current_current.I1 > prev_current.I1 * 1.8 || current_current.I1 < prev_current.I1 * 0.2)) spike_I = 1;
avg_L1 += voltage_buffer_L1[i]; if (prev_current.I2 != 0 && (current_current.I2 > prev_current.I2 * 1.8 || current_current.I2 < prev_current.I2 * 0.2)) spike_I = 1;
avg_L2 += voltage_buffer_L2[i]; if (prev_current.I3 != 0 && (current_current.I3 > prev_current.I3 * 1.8 || current_current.I3 < prev_current.I3 * 0.2)) spike_I = 1;
avg_L3 += voltage_buffer_L3[i];
}
avg_L1 /= voltage_buffer_items;
avg_L2 /= voltage_buffer_items;
avg_L3 /= voltage_buffer_items;
if (fabs(U1 - avg_L1) > avg_L1 * VOLTAGE_FLUCTUATION_THRESHOLD || if(spike_I) {
fabs(U2 - avg_L2) > avg_L2 * VOLTAGE_FLUCTUATION_THRESHOLD || send_current = prev_current;
fabs(U3 - avg_L3) > avg_L3 * VOLTAGE_FLUCTUATION_THRESHOLD) { printf("ORNO: Current spike detected. Sending previous values.\n");
printf("ORNO: Voltage fluctuation detected! Switching to high frequency polling for %d seconds.\n", HIGH_FREQ_MODE_DURATION); } else {
high_frequency_mode_end_time = time(NULL) + HIGH_FREQ_MODE_DURATION; send_current = current_current;
prev_current = current_current;
}
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(spike_P) {
send_power = prev_power;
printf("ORNO: Power spike detected. Sending previous values.\n");
} else {
send_power = current_power;
prev_power = current_power;
} }
/* Validate voltages (150V - 280V is reasonable range for EU grid) */ int spike_W = 0;
if (is_valid_float(U1, 150.0, 280.0) && if (prev_energy.W_Tot != 0 && (current_energy.W_Tot > prev_energy.W_Tot * 1.8 || current_energy.W_Tot < prev_energy.W_Tot)) spike_W = 1;
is_valid_float(U2, 150.0, 280.0) &&
is_valid_float(U3, 150.0, 280.0)) { if(spike_W) {
mqtt_send_U(U1, U2, U3); send_energy = prev_energy;
influx_send_U(U1, U2, U3); printf("ORNO: Energy spike/drop detected. Sending previous values.\n");
} else {
send_energy = current_energy;
prev_energy = current_energy;
}
int spike_F = 0;
if (prev_freq.Freq != 0 && (current_freq.Freq > prev_freq.Freq * 1.05 || current_freq.Freq < prev_freq.Freq * 0.95)) spike_F = 1; // 5% for frequency
if(spike_F) {
send_freq = prev_freq;
printf("ORNO: Frequency spike detected. Sending previous values.\n");
} else {
send_freq = current_freq;
prev_freq = current_freq;
}
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);
printf("ORNO: MQTT: Published voltages\n"); printf("ORNO: MQTT: Published voltages\n");
} else { } else {
printf("ORNO: MQTT: Skipping voltages - invalid values\n"); printf("ORNO: MQTT: Skipping voltages - invalid values\n");
} }
}
printf("ORNO: Currents: L1=%.2f A, L2=%.2f A, L3=%.2f A\n", send_current.I1, send_current.I2, send_current.I3);
usleep(100000); /* 100ms delay between queries */ 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);
// PRADY (Currents) influx_send_I(send_current.I1, send_current.I2, send_current.I3);
memset((char *)reg, 0, sizeof(reg));
num = modbus_read_timed(ctx, 0x16, 6, reg); // ORNO
if (num != 6)
{
printf("ORNO: %x \t\n", 0x16);
printf("ORNO: Failed to read currents: %s\n", modbus_strerror(errno));
}
else
{
I1 = modbus_get_float_abcd(&reg[0]);
I2 = modbus_get_float_abcd(&reg[2]);
I3 = modbus_get_float_abcd(&reg[4]);
printf("ORNO: Currents: L1=%.2f A, L2=%.2f A, L3=%.2f A\n", I1, I2, I3);
/* Validate currents (0-100A is reasonable range for home use) */
if (is_valid_float(I1, 0.0, 100.0) &&
is_valid_float(I2, 0.0, 100.0) &&
is_valid_float(I3, 0.0, 100.0)) {
mqtt_send_I(I1, I2, I3);
influx_send_I(I1, I2, I3);
printf("ORNO: MQTT: Published currents\n"); printf("ORNO: MQTT: Published currents\n");
} else { } else {
printf("ORNO: MQTT: Skipping currents - invalid values\n"); printf("ORNO: MQTT: Skipping currents - invalid values\n");
} }
}
usleep(100000); /* 100ms delay between queries */ 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)) {
memset((char *)reg, 0, sizeof(reg)); mqtt_send_P(send_power.P_Tot, send_power.P1, send_power.P2, send_power.P3);
num = modbus_read_timed(ctx, 0x1c, 8, reg); influx_send_P(send_power.P_Tot, send_power.P1, send_power.P2, send_power.P3);
if (num != 8)
{ // number of read registers is not the one expected
printf("ORNO: %x \t\n", 0x1c);
printf("ORNO: Failed to read: %s\n", modbus_strerror(errno));
}
else
{
P_Tot = modbus_get_float_abcd(&reg[0]);
P1 = modbus_get_float_abcd(&reg[2]);
P2 = modbus_get_float_abcd(&reg[4]);
P3 = modbus_get_float_abcd(&reg[6]);
printf("ORNO: Power: Total=%.3f W, L1=%.3f W, L2=%.3f W, L3=%.3f W\n", P_Tot, P1, P2, P3);
/* Validate power (-25000W to +25000W, allows negative for generation) */
if (is_valid_float(P_Tot, -25000.0, 25000.0) &&
is_valid_float(P1, -10000.0, 10000.0) &&
is_valid_float(P2, -10000.0, 10000.0) &&
is_valid_float(P3, -10000.0, 10000.0)) {
mqtt_send_P(P_Tot, P1, P2, P3);
influx_send_P(P_Tot, P1, P2, P3);
printf("ORNO: MQTT: Published power\n"); printf("ORNO: MQTT: Published power\n");
} else { } else {
printf("ORNO: MQTT: Skipping power - invalid values\n"); printf("ORNO: MQTT: Skipping power - invalid values\n");
} }
}
usleep(100000); /* 100ms delay between queries */
memset((char *)reg, 0, sizeof(reg)); 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);
num = modbus_read_timed(ctx, 0x100, 8, reg); 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)) {
if (num != 8) mqtt_send_W(send_energy.W_Tot, send_energy.W1, send_energy.W2, send_energy.W3);
{ // number of read registers is not the one expected influx_send_W(send_energy.W_Tot, send_energy.W1, send_energy.W2, send_energy.W3);
printf("ORNO: %x \t\n", 0x100);
printf("ORNO: Failed to read: %s\n", modbus_strerror(errno));
}
else
{
W_Tot = modbus_get_float_abcd(&reg[0]);
W1 = modbus_get_float_abcd(&reg[2]);
W2 = modbus_get_float_abcd(&reg[4]);
W3 = modbus_get_float_abcd(&reg[6]);
printf("ORNO: Energy: Total=%.3f kWh, L1=%.3f kWh, L2=%.3f kWh, L3=%.3f kWh\n", W_Tot, W1, W2, W3);
/* Validate energy (0-1000000 kWh is reasonable range) */
if (is_valid_float(W_Tot, 0.0, 1000000.0) &&
is_valid_float(W1, 0.0, 1000000.0) &&
is_valid_float(W2, 0.0, 1000000.0) &&
is_valid_float(W3, 0.0, 1000000.0)) {
mqtt_send_W(W_Tot, W1, W2, W3);
influx_send_W(W_Tot, W1, W2, W3);
printf("ORNO: MQTT: Published energy\n"); printf("ORNO: MQTT: Published energy\n");
} else { } else {
printf("ORNO: MQTT: Skipping energy - invalid values\n"); printf("ORNO: MQTT: Skipping energy - invalid values\n");
} }
}
usleep(10000); /* 10ms delay between queries */ printf("ORNO: Frequency: %.4f Hz\n", send_freq.Freq);
if (is_valid_float(send_freq.Freq, 47.0, 53.0)) {
// CZESTOTLIWOSC (Frequency) mqtt_send_Hz(send_freq.Freq);
memset((char *)reg, 0, sizeof(reg)); influx_send_Hz(send_freq.Freq);
num = modbus_read_timed(ctx, 0x14, 2, reg); // ORNO
if (num != 2)
{
printf("ORNO: %x \t\n", 0x14);
printf("ORNO: Failed to read frequency: %s\n", modbus_strerror(errno));
}
else
{
Freq = modbus_get_float_abcd(&reg[0]);
printf("ORNO: Frequency: %.4f Hz\n", Freq);
/* Validate frequency (47-53 Hz is reasonable range for EU/US grid) */
if (is_valid_float(Freq, 47.0, 53.0)) {
mqtt_send_Hz(Freq);
influx_send_Hz(Freq);
printf("ORNO: MQTT: Published frequency\n"); printf("ORNO: MQTT: Published frequency\n");
} else { } else {
printf("ORNO: MQTT: Skipping frequency - invalid value\n"); printf("ORNO: MQTT: Skipping frequency - invalid value\n");
} }
} }
modbus_close(ctx);
modbus_free(ctx);
} }
if (do_sun2k) if (do_sun2k)
{ {

BIN
modborno3

Binary file not shown.

View File

@@ -4,11 +4,11 @@ Documentation=file:///home/ms/projekty/python3/modebus/ornoserial3/CONFIG.md
After=network.target mosquitto.service After=network.target mosquitto.service
[Service] [Service]
Type=oneshot Type=simple
User=ms User=ms
Group=dialout Group=dialout
WorkingDirectory=/home/ms/projekty/python3/modebus/ornoserial3 WorkingDirectory=/home/bin
ExecStart=/home/ms/projekty/python3/modebus/ornoserial3/modborno3 ExecStart=/home/ms/bin/modborno3
StandardOutput=journal StandardOutput=journal
StandardError=journal StandardError=journal
SyslogIdentifier=read-energy SyslogIdentifier=read-energy