Compare commits

...

2 Commits

Author SHA1 Message Date
ms
886cecf523 gtignore 2026-02-08 21:24:03 +01:00
ms
cec575c435 dodatkowe modyfikacje dla zapobieżenia zarowym odczytow 2026-02-08 21:17:40 +01:00
5 changed files with 254 additions and 173 deletions

44
.gitignore vendored
View File

@@ -13,3 +13,47 @@ my_gitea.crt
# Log files
*.log
# --- Systemowe (Linux/macOS/Windows) ---
.DS_Store
Thumbs.db
*~
*.swp
*.tmp
# --- Visual Studio Code ---
.vscode/
# Jeśli chcesz współdzielić ustawienia debugowania, zakomentuj powyższe,
# a odkomentuj poniższe:
# !.vscode/launch.json
# !.vscode/tasks.json
# --- Logi i bazy danych ---
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
*.sqlite
# --- Sekrety (BARDZO WAŻNE) ---
# Nigdy nie wysyłaj haseł, kluczy API i tokenów!
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
*.pem
*.key
# --- Pakiety i biblioteki (zależnie od języka) ---
# Node.js
node_modules/
# Python
__pycache__/
*.py[cod]
*$py.class
venv/
.venv/
# C/C++
*.o
*.out
build/

View File

@@ -1 +1,4 @@
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 <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 */
/* ============================================ */
@@ -406,6 +415,13 @@ int main(int argc, char *argv[])
int do_orno = READ_ORNO;
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_L2[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)
{
//Create a new RTU context with proper serial parameters (in this example,
//device name /dev/ttyS0, baud rate 9600, no parity bit, 8 data bits, 1 stop bit)
//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 (to 2)
//Set the Modbus address of the remote slave
modbus_set_slave(ctx, ORNO_SLAVE);
if (!ctx)
{
@@ -455,210 +470,229 @@ int main(int argc, char *argv[])
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_set_response_timeout(ctx, 0, 900000); /* 0.9s */
modbus_set_byte_timeout(ctx, 0, ORNO_BYTE_TIMEOUT);
/* Display current configuration */
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);
printf("ORNO: RTS Delay and Timeouts configured.\n");
uint16_t reg[32]; // will store read registers values
uint16_t reg2[2]; // will store read registers values
float d = 0.0;
uint16_t reg[32];
int num;
int num = 0;
int proba = 0;
float U1, U2, U3;
float I1, I2, I3;
float P_Tot, P1, P2, P3;
float W_Tot, W1, W2, W3;
float Freq;
// ---- READ ALL ORNO VALUES ----
long l = 0;
/* Flush serial buffer and wait for device to be ready */
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));
// VOLTAGES
num = modbus_read_timed(ctx, 0xe, 6, reg);
if (num == 6) {
current_voltage.U1 = modbus_get_float_abcd(&reg[0]);
current_voltage.U2 = modbus_get_float_abcd(&reg[2]);
current_voltage.U3 = modbus_get_float_abcd(&reg[4]);
} else {
printf("ORNO: Failed to read voltages: %s\n", modbus_strerror(errno));
current_voltage = prev_voltage; // On error, use previous values
}
else
{
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);
usleep(100000);
// Add to circular buffer
voltage_buffer_L1[voltage_buffer_index] = U1;
voltage_buffer_L2[voltage_buffer_index] = U2;
voltage_buffer_L3[voltage_buffer_index] = U3;
voltage_buffer_index = (voltage_buffer_index + 1) % VOLTAGE_BUFFER_SIZE;
if (voltage_buffer_items < VOLTAGE_BUFFER_SIZE) {
voltage_buffer_items++;
// CURRENTS
num = modbus_read_timed(ctx, 0x16, 6, reg);
if (num == 6) {
current_current.I1 = modbus_get_float_abcd(&reg[0]);
current_current.I2 = modbus_get_float_abcd(&reg[2]);
current_current.I3 = modbus_get_float_abcd(&reg[4]);
} 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;
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;
int spike_I = 0;
if (prev_current.I1 != 0 && (current_current.I1 > prev_current.I1 * 1.8 || current_current.I1 < prev_current.I1 * 0.2)) spike_I = 1;
if (prev_current.I2 != 0 && (current_current.I2 > prev_current.I2 * 1.8 || current_current.I2 < prev_current.I2 * 0.2)) spike_I = 1;
if (prev_current.I3 != 0 && (current_current.I3 > prev_current.I3 * 1.8 || current_current.I3 < prev_current.I3 * 0.2)) spike_I = 1;
if (fabs(U1 - avg_L1) > avg_L1 * VOLTAGE_FLUCTUATION_THRESHOLD ||
fabs(U2 - avg_L2) > avg_L2 * VOLTAGE_FLUCTUATION_THRESHOLD ||
fabs(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);
high_frequency_mode_end_time = time(NULL) + HIGH_FREQ_MODE_DURATION;
if(spike_I) {
send_current = prev_current;
printf("ORNO: Current spike detected. Sending previous values.\n");
} else {
send_current = current_current;
prev_current = current_current;
}
/* Validate voltages (150V - 280V is reasonable range for EU grid) */
if (is_valid_float(U1, 150.0, 280.0) &&
is_valid_float(U2, 150.0, 280.0) &&
is_valid_float(U3, 150.0, 280.0)) {
mqtt_send_U(U1, U2, U3);
influx_send_U(U1, U2, U3);
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;
}
int spike_W = 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;
if(spike_W) {
send_energy = prev_energy;
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");
} else {
printf("ORNO: MQTT: Skipping voltages - invalid values\n");
}
}
usleep(100000); /* 100ms delay between queries */
// PRADY (Currents)
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: 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);
printf("ORNO: MQTT: Published currents\n");
} else {
printf("ORNO: MQTT: Skipping currents - invalid values\n");
}
}
usleep(100000); /* 100ms delay between queries */
memset((char *)reg, 0, sizeof(reg));
num = modbus_read_timed(ctx, 0x1c, 8, reg);
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: 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);
printf("ORNO: MQTT: Published power\n");
} else {
printf("ORNO: MQTT: Skipping power - invalid values\n");
}
}
usleep(100000); /* 100ms delay between queries */
memset((char *)reg, 0, sizeof(reg));
num = modbus_read_timed(ctx, 0x100, 8, reg);
if (num != 8)
{ // number of read registers is not the one expected
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: 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);
printf("ORNO: MQTT: Published energy\n");
} else {
printf("ORNO: MQTT: Skipping energy - invalid values\n");
}
}
usleep(10000); /* 10ms delay between queries */
// CZESTOTLIWOSC (Frequency)
memset((char *)reg, 0, sizeof(reg));
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: 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);
printf("ORNO: MQTT: Published frequency\n");
} else {
printf("ORNO: MQTT: Skipping frequency - invalid value\n");
}
}
modbus_close(ctx);
modbus_free(ctx);
}
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
[Service]
Type=oneshot
Type=simple
User=ms
Group=dialout
WorkingDirectory=/home/ms/projekty/python3/modebus/ornoserial3
ExecStart=/home/ms/projekty/python3/modebus/ornoserial3/modborno3
WorkingDirectory=/home/bin
ExecStart=/home/ms/bin/modborno3
StandardOutput=journal
StandardError=journal
SyslogIdentifier=read-energy