diff --git a/cc-modb_orno3.sh b/cc-modb_orno3.sh index e0875d6..ae2b0f0 100755 --- a/cc-modb_orno3.sh +++ b/cc-modb_orno3.sh @@ -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 diff --git a/modb_orno3.c b/modb_orno3.c index 05cfdee..501bc88 100644 --- a/modb_orno3.c +++ b/modb_orno3.c @@ -12,6 +12,15 @@ #include #include +/* ============================================ */ +/* 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; - - 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)); + // ---- READ ALL ORNO VALUES ---- + + // VOLTAGES + num = modbus_read_timed(ctx, 0xe, 6, reg); + if (num == 6) { + current_voltage.U1 = modbus_get_float_abcd(®[0]); + current_voltage.U2 = modbus_get_float_abcd(®[2]); + current_voltage.U3 = modbus_get_float_abcd(®[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(®[0]); - U2 = modbus_get_float_abcd(®[2]); - U3 = modbus_get_float_abcd(®[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(®[0]); + current_current.I2 = modbus_get_float_abcd(®[2]); + current_current.I3 = modbus_get_float_abcd(®[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(®[0]); + current_power.P1 = modbus_get_float_abcd(®[2]); + current_power.P2 = modbus_get_float_abcd(®[4]); + current_power.P3 = modbus_get_float_abcd(®[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(®[0]); + current_energy.W1 = modbus_get_float_abcd(®[2]); + current_energy.W2 = modbus_get_float_abcd(®[4]); + current_energy.W3 = modbus_get_float_abcd(®[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(®[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; + } + + 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) */ - 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_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(®[0]); - I2 = modbus_get_float_abcd(®[2]); - I3 = modbus_get_float_abcd(®[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(®[0]); - P1 = modbus_get_float_abcd(®[2]); - P2 = modbus_get_float_abcd(®[4]); - P3 = modbus_get_float_abcd(®[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(®[0]); - W1 = modbus_get_float_abcd(®[2]); - W2 = modbus_get_float_abcd(®[4]); - W3 = modbus_get_float_abcd(®[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(®[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) { diff --git a/modborno3 b/modborno3 index bb552e9..229ca6f 100755 Binary files a/modborno3 and b/modborno3 differ diff --git a/read-energy.service b/read-energy.service index 7ae5e0f..b8e79f9 100644 --- a/read-energy.service +++ b/read-energy.service @@ -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