Compare commits

...

15 Commits

Author SHA1 Message Date
ms
b68a950062 Update modb_orno_tester.c
ocena szybkosci oparta tylko na poprawnych ramkach ignorowane ramki z blednym CRC lub timoutem
2026-02-17 14:01:59 +01:00
ms
7a03a794ba Add modb_orno_tester.c
program do testowania szybkości pobierania pomiarów tylko napięć z ORNO i SUN2K aby podjąć decyzję z którego urządzenia odczytywać napięcia
2026-02-17 13:15:46 +01:00
ms
fd8dce7535 Update modb_orno3.c
W trybie zwiększonej fluktuacji przyspieszamy wyłącznie odczyt napięc.
Poprawka wygenerowana przez qwen3_coder
2026-02-17 13:12:52 +01:00
ms
3078bbcf3f poprawka do odczytywania z orno 2026-02-15 23:08:33 +01:00
ms
7220d3e750 zmiana w modb_orno3.c i dodanie skryptu usuniecie_pola_highfluct.sh 2026-02-15 22:22:01 +01:00
ms
bc399e0044 Po upływie HIGH_FREQ_MODE_DURATION sekund od wykrycia fluktuacji napięcia:
- Wysyłany jest komunikat MQTT na topic /energy/orno/fluct z wartością "off"
  - Wysyłany jest zapis do InfluxDB z tagiem highfluct=end i wartością highfluct=0
  - Flaga jest resetowana, aby powiadomienie wysłało się tylko raz
2026-02-15 00:29:54 +01:00
ms
ae444a10fc Mapowanie rejestrów SUN2K do jednolitego formatu ORNO 2026-02-15 00:04:34 +01:00
ms
8f3756b1fe dodane logowanie wysyłanych danych do InfluxDB (przez --log)
wysylanie U_A, U_B, U_C do MQTT w formacie JSON podobnie jak dla innych pomiarów (np. Hz)
wysylanie U_A, U_B, U_C do InfluxDB w batchu razem z innymi pomiarami (nie osobno)
2026-02-14 23:08:04 +01:00
ms
0524e7284d Fix spike detection bug causing stuck values
When a spike was detected in voltage, current, power, energy, or frequency,
the code sent previous values but never updated the prev_* variables.
This caused the system to get stuck reporting old values indefinitely
after any significant measurement change.

Now all prev_* variables are always updated after spike detection,
ensuring values can change again after being filtered.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 21:09:30 +01:00
ms
2b16211ef2 Fix sprintf overflows, integer sign handling, and clean up dead code
- Replace all sprintf with snprintf for buffer safety
- Fix rgI32/rgI16 sign extension using int32_t/int16_t casts
- Fix rgU32/rgU16 to use proper uint types and %u format
- Remove unused mbReg_Orno[] array and individual influx_send_* functions
- Fix MQTT topic for voltage fluctuation to match /energy/orno/ convention

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 20:38:45 +01:00
ms
44aceebae6 jakis commit 2026-02-14 20:20:51 +01:00
ms
912878d6e6 modyfikacje przez claude 2026-02-14 19:40:38 +01:00
ms
aa31532d8c 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>
2026-02-14 19:32:04 +01:00
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
10 changed files with 1538 additions and 266 deletions

View File

@@ -11,7 +11,12 @@
"Bash(1 echo \"Test wykonany. Analiza wyników:\" echo \"\" echo \"✓ POMYŚLNIE ODCZYTANE REJESTRY:\" grep \"OK.*elapsed\" /tmp/sun2k_test.log)", "Bash(1 echo \"Test wykonany. Analiza wyników:\" echo \"\" echo \"✓ POMYŚLNIE ODCZYTANE REJESTRY:\" grep \"OK.*elapsed\" /tmp/sun2k_test.log)",
"Read(//tmp/**)", "Read(//tmp/**)",
"Bash(for i in 1 2)", "Bash(for i in 1 2)",
"Bash(ls:*)" "Bash(ls:*)",
"Bash(git add:*)",
"Bash(git commit:*)",
"Bash(git push:*)",
"Bash(git -c http.sslVerify=false push)",
"Bash(git config:*)"
] ]
} }
} }

44
.gitignore vendored
View File

@@ -13,3 +13,47 @@ my_gitea.crt
# Log files # Log files
*.log *.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 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

464
kimi_analyse.md Normal file
View File

@@ -0,0 +1,464 @@
╭─── Claude Code v2.1.42 ────────────────────────────────────────────────────────────────────────────────╮
│ │ Tips for getting started │
│ Welcome back! │ Run /init to create a CLAUDE.md file with instructions for … │
│ │ ──────────────────────────────────────────────────────────── │
│ │ Recent activity │
│ ▐▛███▜▌ │ No recent activity │
│ ▝▜█████▛▘ │ │
│ ▘▘ ▝▝ │ │
│ kimi-k2.5:cloud · API Usage Billing │ │
│ ~/projekty/modborno3 │ │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────╯
/model to try Opus 4.6
analyse modb_orno3.c
● Read 1 file (ctrl+o to expand)
● Analysis of modb_orno3.c
Overview
This is a C program that reads energy data from two Modbus RTU devices:
- ORNO - 3-phase energy meter (voltage, current, power, energy, frequency)
- SUN2000 - Huawei solar inverter
Data is published to MQTT (using Eclipse Mosquitto) and InfluxDB v2.
---
Architecture
Modbus Communication
- Uses libmodbus for RTU serial communication via /dev/ttyUSB0
- ORNO: slave address 2, even parity ('E'), RTS delay 5ms
- SUN2000: slave address 3, no parity ('N'), RTS delay 5ms
- Timing parameters configurable via #define directives (lines 41-50)
Data Flow
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ ORNO │ │ SUN2000 │ │ Output │
│ (meter) │ │ (inverter) │ │ │
└──────┬──────┘ └──────┬──────┘ ├─> MQTT │
│ │ ├─> InfluxDB │
└───────┬───────────┘ │ (HTTP) │
│ └─────────────┘
modbus_read_registers()
---
Key Features
1. Voltage Fluctuation Detection (lines 546-572)
- Circular buffer of 12 samples tracks voltage history
- Detects fluctuations >5% from average
- Triggers high-frequency mode (300s duration, 10ms polling)
2. Spike Detection (lines 591-649)
- Validates readings against previous values
- Rejects changes >80% (factor of 1.8x) for voltage, current, power
- Rejects energy decreases (line 630)
- Frequency validated within ±5%
3. Range Validation (lines 360-375)
- Checks for NaN/Inf values
- Validates against min/max thresholds (e.g., voltage 150-280V)
---
Register Mappings
ORNO registers (lines 128-140):
- Voltages: 0x0E, 0x10, 0x12 (L1, L2, L3)
- Currents: 0x16 (start)
- Power: 0x1C (total + per-phase)
- Energy: 0x100 (total + per-phase)
- Frequency: 0x14
SUN2000 registers (lines 105-126):
- Startup/shutdown times, device status, alarms
- PV input power, phase voltages, peak/active/reactive power
- Grid frequency, temperature, energy yields
---
Security Concerns
Critical: Line 65 contains a hardcoded InfluxDB token:
#define INFLUX_TOKEN
"BCIZ6kcCAVgpcwSfU0PBS7m0Zb6an93kuOtizbEtlXub-uaoYp4dmIQBQYaJCv8_KE4QYYZ08jxtpaZ3TUWP-Q=="
Other issues:
- Hardcoded MQTT broker (10.1.1.1:1883) - no TLS
- InfluxDB connection uses plaintext HTTP (port 5086)
- No authentication on MQTT (no username/password)
---
Code Quality Observations
Strengths:
- Good error handling for Modbus operations
- Timing instrumentation (modbus_read_timed())
- Previous-value fallback on read failures
- Configurable via compile-time defines
Weaknesses:
- Uses sprintf() without bounds checking (potential buffer overflow)
- No free(buf) in mosq_test() (line 408) - memory leak
- Mixed Polish/English in comments
- mosq_test() declared to return int but has no return statement
- main() uses do-while with exit(1) on errors - connection leaks on ORNO failure
---
Potential Bugs
1. Line 630 - Energy spike detection logic:
if (prev_energy.W_Tot != 0 && (current_energy.W_Tot > prev_energy.W_Tot * 1.8 || current_energy.W_Tot <
prev_energy.W_Tot))
1. This triggers on ANY decrease in energy (not just spikes), which may be intentional for a
non-decreasing counter.
2. Line 565-567 - Division by zero risk if voltage_buffer_items is 0 (protected by check on line 551,
but edge case exists).
3. Line 797 - asctime() returns pointer to static buffer - not thread-safe.
4. Line 303 - strlen(data) with potential unterminated string if influx_send_* functions receive bad
input.
---
Recommendations
1. Move credentials to environment variables or config file
2. Add TLS support for MQTT and InfluxDB
3. Replace sprintf() with snprintf()
4. Add signal handling for clean shutdown
5. Consider using modbus_read_registers() batch reads for SUN2000 to reduce round-trips
✻ Sautéed for 55s
✻ Sautéed for 55s
/model
⎿ Set model to opus (kimi-k2.5:cloud)
analyse modb_orno3.c
● I already have the file content from our previous conversation. Here's a comprehensive analysis:
Code Analysis: modb_orno3.c
Purpose
A Modbus RTU data collector that reads energy measurements from two devices:
- ORNO (3-phase electricity meter) - voltages, currents, power, energy, frequency
- SUN2000 (Huawei solar inverter) - status, alarms, PV power, temperatures, yields
Publishes data to MQTT (Eclipse Mosquitto) and InfluxDB v2.
---
Architecture
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ ORNO │ │ Program │ │ MQTT │
│ (addr 2) │─────>│ modb_orno3 │─────>│ Broker │
│ 9600,E,8,1 │ │ │ │ 10.1.1.1 │
└─────────────┘ │ │ └─────────────┘
│ │
┌─────────────┐ │ │ ┌─────────────┐
│ SUN2000 │ │ │ │ InfluxDB │
│ (addr 3) │─────>│ │─────>│ 10.1.1.1 │
│ 9600,N,8,1 │ └──────────────┘ │ :5086 │
└─────────────┘ └─────────────┘
---
Key Features
┌─────────────────────┬────────────────────────────────────────────────────────────────────────┐
│ Feature │ Implementation │
├─────────────────────┼────────────────────────────────────────────────────────────────────────┤
│ Spike Detection │ Rejects values changing >80% (1.8x factor) for U/I/P │
├─────────────────────┼────────────────────────────────────────────────────────────────────────┤
│ Voltage Fluctuation │ Circular buffer (12 samples), triggers high-freq mode on >5% deviation │
├─────────────────────┼────────────────────────────────────────────────────────────────────────┤
│ Data Validation │ NaN/Inf checks, min/max range validation │
├─────────────────────┼────────────────────────────────────────────────────────────────────────┤
│ Retry Logic │ Up to 10 retries per SUN2000 register │
├─────────────────────┼────────────────────────────────────────────────────────────────────────┤
│ Timed Reads │ Logs Modbus operation duration │
└─────────────────────┴────────────────────────────────────────────────────────────────────────┘
---
Critical Security Issues
1. Hardcoded InfluxDB Token (line 65)
#define INFLUX_TOKEN
"BCIZ6kcCAVgpcwSfU0PBS7m0Zb6an93kuOtizbEtlXub-uaoYp4dmIQBQYaJCv8_KE4QYYZ08jxtpaZ3TUWP-Q=="
- Risk: Credential exposure in source control
- Fix: Move to environment variable or config file
2. Unencrypted Communications
- MQTT: Plaintext on port 1883 (no TLS)
- InfluxDB: Plaintext HTTP on port 5086
- No MQTT authentication (no username/password)
3. Hardcoded IP Addresses
#define MQTT_BROKER "10.1.1.1"
#define INFLUX_HOST "10.1.1.1"
---
Code Quality Issues
┌──────────────────────┬───────────────┬──────────────────────────────────────────────┐
│ Issue │ Line │ Problem │
├──────────────────────┼───────────────┼──────────────────────────────────────────────┤
│ Memory leak │ 398-407 │ mosq_test() allocates buf but never frees it │
├──────────────────────┼───────────────┼──────────────────────────────────────────────┤
│ Missing return │ 393-407 │ mosq_test() declared int but has no return │
├──────────────────────┼───────────────┼──────────────────────────────────────────────┤
│ Buffer overflow risk │ 226, 234, etc │ sprintf() without bounds checking │
├──────────────────────┼───────────────┼──────────────────────────────────────────────┤
│ Mixed languages │ 25, 44, etc │ Polish/English comments mixed │
├──────────────────────┼───────────────┼──────────────────────────────────────────────┤
│ Dead code │ 903 │ //mosq_test() commented out │
└──────────────────────┴───────────────┴──────────────────────────────────────────────┘
---
Potential Bugs
1. Energy Spike Detection Logic (line 630)
if (prev_energy.W_Tot != 0 && (current_energy.W_Tot > prev_energy.W_Tot * 1.8 || current_energy.W_Tot <
prev_energy.W_Tot))
This rejects ANY decrease in energy (not just spikes), which may reject valid data if the counter rolls
over or resets.
2. Frequency Threshold Inconsistency
- Line 569: ±5% threshold for spike detection
- But line 641 uses 1.05/0.95 (also 5%)
- Line 688 validates 47-53 Hz (±6% from 50 Hz)
3. InfluxDB Line Protocol Syntax Issues
Line 323 (missing comma between tags and fields):
"orno,device=orno,pomiar=voltage, L1=%.2f,L2=%.2f,L3=%.2f"
Should be:
"orno,device=orno,pomiar=voltage L1=%.2f,L2=%.2f,L3=%.2f"
4. asctime() Buffer Issue (line 797)
sprintf(str_buf, "\"%s\"", asctime(timeinfo));
asctime() returns pointer to static buffer - contains newline which is then manipulated (line 798-799).
Not thread-safe.
5. Inconsistent Scaling in ORNO Registers
Line 132: L3 Volt has scale: 10 while L1/L2 have scale: 1 - potential copy-paste error?
---
Configuration (lines 26-66)
#define READ_LOOP true // true = continuous 5s polling
#define VOLTAGE_FLUCTUATION_THRESHOLD 0.05 // 5%
#define HIGH_FREQ_MODE_DURATION 300 // 300 seconds
#define ORNO_RTS_DELAY 5000 // 5ms
#define SUN2K_RTS_DELAY 5000 // 5ms
#define DELAY_BETWEEN_DEVICES 10000 // 10ms between devices
---
Modbus Register Maps
ORNO (mbReg_Orno[]) - Uses function code 3 (holding registers):
┌───────────┬─────────┬──────┬─────────────────┐
│ Register │ Address │ Type │ Scale │
├───────────┼─────────┼──────┼─────────────────┤
│ L1 Volt │ 0x000E │ U32 │ 1 │
├───────────┼─────────┼──────┼─────────────────┤
│ L2 Volt │ 0x0010 │ U32 │ 1 │
├───────────┼─────────┼──────┼─────────────────┤
│ L3 Volt │ 0x0012 │ U32 │ 10 (suspicious) │
├───────────┼─────────┼──────┼─────────────────┤
│ Tot Power │ 0x001C │ U32 │ 1 │
├───────────┼─────────┼──────┼─────────────────┤
│ ... │ ... │ ... │ ... │
└───────────┴─────────┴──────┴─────────────────┘
SUN2000 (mbReg[]) - Various data types:
- rgData - timestamps (lines 107-109)
- rgI32 - signed 32-bit (power values)
- rgU32 - unsigned 32-bit (energy counters)
- rgI16 - signed 16-bit (temperature)
- rgU16 - unsigned 16-bit (status codes)
---
Recommendations
1. Security: Move credentials to environment variables
2. Add TLS: Configure MQTT and InfluxDB with TLS certificates
3. Fix InfluxDB format: Remove comma between tags/fields in line protocol
4. Buffer safety: Replace sprintf() with snprintf()
5. Memory: Fix leak in mosq_test() or remove unused function
6. Scaling: Verify L3 Volt scale (10 vs 1) for ORNO
7. Energy logic: Consider rollover handling for energy counters
8. Logging: Add structured logging instead of printf
---
Summary
This is functional embedded systems code for energy monitoring with reasonable error handling and data
validation. The main concerns are security (hardcoded credentials) and potential data quality issues
(InfluxDB line protocol format, scaling inconsistencies). The spike detection and voltage fluctuation
features show thoughtful defensive programming.
✻ Sautéed for 52s
--------------------------------------------------------
/model
⎿ Set model to opus (claude-opus-4-6)
analyse modb_orno3.c
⎿ Not logged in · Please run /login
run /login
⎿ Not logged in · Please run /login
run /login
⎿ Not logged in · Please run /login
/login
⎿ Login successful
analyse modb_orno3.c
● Searched for 1 pattern, read 1 file (ctrl+o to expand)
● Analiza modb_orno3.c
Opis ogólny
Program w C do odczytu danych z dwóch urządzeń Modbus RTU przez port szeregowy:
- ORNO (slave 2) — trójfazowy licznik energii
- SUN2000 (slave 3) — falownik Huawei SUN2000
Odczytane dane są wysyłane do MQTT (broker 10.1.1.1:1883) i InfluxDB v2 (10.1.1.1:5086).
---
Architektura
┌──────────────┬──────────────────────────────────────────────────────┐
│ Warstwa │ Opis │
├──────────────┼──────────────────────────────────────────────────────┤
│ Modbus RTU │ libmodbus, port /dev/ttyUSB0, 9600 baud │
├──────────────┼──────────────────────────────────────────────────────┤
│ MQTT │ libmosquitto, topic /energy/orno/* i /energy/SUN2K │
├──────────────┼──────────────────────────────────────────────────────┤
│ InfluxDB │ Surowe HTTP POST na /api/v2/write, line protocol │
├──────────────┼──────────────────────────────────────────────────────┤
│ Pętla główna │ do/while co 5s (normalnie) lub 10ms (tryb high-freq) │
└──────────────┴──────────────────────────────────────────────────────┘
---
Znalezione problemy i uwagi
1. Wyciek tokenu InfluxDB (linia 65)
Token jest zahardkodowany w kodzie źródłowym. Powinien być w zmiennej środowiskowej lub pliku
konfiguracyjnym.
2. Bug: modbus_set_slave przed sprawdzeniem ctx (linia 459-460)
modbus_set_slave(ctx, ORNO_SLAVE); // linia 459 - ctx może być NULL
if (!ctx) { ... } // linia 460 - sprawdzenie za późno
modbus_set_slave zostanie wywołane na NULL pointer zanim nastąpi walidacja. Crash gwarantowany jeśli
modbus_new_rtu zawiedzie.
3. Bug w InfluxDB line protocol - nadmiarowy przecinek (linia 323)
"orno,device=orno,pomiar=voltage, L1=%.2f,L2=%.2f,L3=%.2f"
// ^ spacja+przecinek zamiast spacji
Powinno być pomiar=voltage L1=... (spacja oddziela tagi od pól). Dodatkowy przecinek po voltage powoduje
błąd parsowania w InfluxDB — dane napięcia prawdopodobnie nie są zapisywane.
4. Tryb high-frequency polling — 10ms bez throttlingu (linia 897)
Przy wykryciu fluktuacji napięcia program przełącza się na usleep(10000) (10ms) na 300 sekund. W tym
trybie:
- Program robi ~100 odczytów/s po Modbus RTU (9600 baud to ~1 odczyt/s realnie)
- Każdy odczyt otwiera nowe połączenie TCP do InfluxDB → tysiące krótkich połączeń
- Timeout Modbus to 0.9s — więc realna częstotliwość i tak będzie ~1/s, ale logika jest myląca
5. Brak modbus_set_slave po stronie SUN2K idzie przed ctx check (linia 720 vs 714)
Tutaj jest OK — modbus_set_slave jest po sprawdzeniu ctx. Ale dla ORNO (pkt 2) jest bug.
6. Połączenie TCP do InfluxDB tworzone na każdy pomiar (linia 264-318)
Każde wywołanie influx_send_post otwiera nowy socket, wysyła dane i zamyka. W normalnym trybie to ~6
połączeń co 5s (OK), ale w trybie high-freq to setki na minutę. Lepiej: batch writes lub persistent
connection.
7. Brak odczytu odpowiedzi z InfluxDB (linia 317)
Po wysłaniu danych socket jest zamykany bez czytania odpowiedzi HTTP. Nie wiadomo czy zapis się powiódł
(np. 401 Unauthorized, 400 Bad Request).
8. sprintf bez ograniczenia bufora (linie 227, 235, 243, 251, 259, 401)
Używane sprintf zamiast snprintf — potencjalny buffer overflow przy nieoczekiwanych danych float (np.
bardzo duże wartości).
9. Spike detection nie działa dla ujemnych mocy (linia 619)
current_power.P_Tot > prev_power.P_Tot * 1.8 || current_power.P_Tot < prev_power.P_Tot * 0.2
Jeśli moc jest ujemna (oddawanie do sieci), mnożenie przez 1.8 daje bardziej ujemną wartość, a 0.2 mniej
ujemną — logika się odwraca.
10. Energy spike — asymetryczna walidacja (linia 630)
current_energy.W_Tot > prev_energy.W_Tot * 1.8 || current_energy.W_Tot < prev_energy.W_Tot
Górny próg to 180%, ale dolny to dokładnie prev (jakikolwiek spadek = spike). Energia powinna być
monotoniczne rosnąca, więc logika dolnego progu jest OK, ale wartość 1.8 dla górnego może być za wysoka.
11. mosq_test() — memory leak (linia 398)
malloc(64) bez free. Drobnostka bo funkcja nie jest używana (zakomentowana w main).
12. Różne parametry seryjne ORNO vs SUN2K
- ORNO: 9600, Even parity, 8, 1 (linia 457)
- SUN2K: 9600, No parity, 8, 1 (linia 713)
To jest poprawne (Huawei SUN2000 domyślnie używa N-8-1, ORNO domyślnie E-8-1), ale warto mieć świadomość
że oba urządzenia mają różne konfiguracje.
13. Niestandardowy include (linia 4)
#include </usr/include/modbus/modbus-rtu.h>
Powinno być #include <modbus/modbus-rtu.h> — absolutna ścieżka uniemożliwia przenośność.
---
Podsumowanie priorytetów napraw
┌───────────┬────────────────────────────────────────────────────┐
│ Priorytet │ Problem │
├───────────┼────────────────────────────────────────────────────┤
│ Krytyczny │ Bug NULL pointer dereference ORNO (pkt 2) │
├───────────┼────────────────────────────────────────────────────┤
│ Krytyczny │ InfluxDB line protocol — zły format napięć (pkt 3) │
├───────────┼────────────────────────────────────────────────────┤
│ Wysoki │ Token InfluxDB w kodzie (pkt 1) │
├───────────┼────────────────────────────────────────────────────┤
│ Wysoki │ Spike detection dla ujemnych mocy (pkt 9) │
├───────────┼────────────────────────────────────────────────────┤
│ Średni │ Brak odczytu odpowiedzi InfluxDB (pkt 7) │
├───────────┼────────────────────────────────────────────────────┤
│ Średni │ sprintf → snprintf (pkt 8) │
├───────────┼────────────────────────────────────────────────────┤
│ Niski │ Batching InfluxDB writes (pkt 6) │
├───────────┼────────────────────────────────────────────────────┤
│ Niski │ Niestandardowy include path (pkt 13) │
└───────────┴────────────────────────────────────────────────────┘
Chcesz żebym naprawił którekolwiek z tych problemów?
✻ Cooked for 52s
──────────────────────────────────────────────────────────────────────────────────────────────────────────
napraw krytyczne problemy (pkt 2 i 3
──────────────────────────────────────────────────────────────────────────────────────────────────────
? for shortcuts

68
kimi_analyse2.md Normal file
View File

@@ -0,0 +1,68 @@
frequency of reports of orno measuring is very rare , value not changes. try to analyse this problem
● I'll analyze the code to understand the ORNO measuring report frequency issue. Let me first read the relevant file.
● Read 1 file (ctrl+o to expand)
● I analyzed the code and found two critical bugs that explain the rare reports and stuck values:
Problem 1: Spike Detection Logic Bug (Causes "Values Not Changing")
Lines 618-624, 632-638, 644-650, 656-662, and 668-674 have a logic error. When a spike is detected, the code sends previous
values but never updates the stored previous value. This means once a spike is detected, the system reports old values forever.
Example from voltage check:
if(spike_U) {
send_voltage = prev_voltage; // Send old value
printf("ORNO: Voltage spike detected. Sending previous values.\n");
// BUG: prev_voltage is NOT updated here!
} else {
send_voltage = current_voltage;
prev_voltage = current_voltage; // Only updated when NO spike
}
Impact: If your voltage/current/power changes by more than 80% (or frequency by 5%), the system will get stuck reporting the
old values indefinitely.
Problem 2: SUN2K Retry Loop (Causes "Rare Reports")
Lines 796-799 show SUN2K has a retry loop with up to 10 attempts per register:
do {
num = modbus_read_timed(ctx, mbReg[i].ireg, mbReg[i].num_reg, reg);
} while ((num != mbReg[i].num_reg) && (proba++ < 10));
With a 0.9s timeout (line 766) and ~19 registers to read, if SUN2K is unresponsive this can delay each loop iteration by up to
~3 minutes (19 registers × 10 retries × 0.9s = 171s).
Since ORNO is read before SUN2K in the same loop, ORNO reports become rare when SUN2K has communication issues.
Recommendations
1. Fix spike detection - Update prev_* values even when spikes are detected, or the values will never update after any
significant change:
// Current buggy code:
if(spike_U) {
send_voltage = prev_voltage;
} else {
send_voltage = current_voltage;
prev_voltage = current_voltage; // Missing in spike branch!
}
// Fixed version:
if(spike_U) {
printf("ORNO: Voltage spike detected. Using previous values.\n");
}
send_voltage = current_voltage; // Always use current
prev_voltage = current_voltage; // Always update prev
2. Reduce SUN2K impact - Either:
- Reduce proba limit from 10 to 2-3 attempts
- Reduce response timeout from 900ms to 300ms
- Run SUN2K in a separate thread or process
- Disable SUN2K if not needed (#define READ_SUN2K false)
3. Add debugging - The code already has good logging. Check if you see "spike detected" messages or SUN2K timeout errors in
your logs.
The combination of these bugs explains why values appear stuck (spike detection) and reports are infrequent (SUN2K delays).
✻ Sautéed for 3m 13s

File diff suppressed because it is too large Load Diff

370
modb_orno_tester.c Normal file
View File

@@ -0,0 +1,370 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <modbus/modbus-rtu.h>
#include <errno.h>
#include <time.h>
#include <unistd.h>
#include <sys/time.h>
#include <math.h>
#include <limits.h>
/* Konfiguracja */
#define USB_DEV_DEFAULT "/dev/ttyUSB0"
#define ORNO_SLAVE_ADR 2
#define SUN2000_SLAVE_ADR 3
#define NUM_READINGS 10 /* Liczba odczytów do testu */
/* Parametry timing dla ORNO */
#define ORNO_RTS_DELAY 5000
#define ORNO_BYTE_TIMEOUT 2500
/* Parametry timing dla SUN2K */
#define SUN2K_RTS_DELAY 5000
#define SUN2K_BYTE_TIMEOUT 2500
/* Stała dla timeoutu - wartości powyżej tego są uznawane za timeout */
#define TIMEOUT_THRESHOLD_US 100000 /* 100ms */
/* Struktura do przechowywania wyników testu */
typedef struct {
long total_time_us;
long min_time_us;
long max_time_us;
double avg_time_ms;
int successful_reads;
int total_reads;
int crc_errors;
int timeouts;
} test_results_t;
/* Timed wrapper for modbus_read_registers - logs start/stop and duration */
long modbus_read_timed(modbus_t *ctx, int addr, int nb, uint16_t *dest, int *success)
{
struct timeval t0, t1;
gettimeofday(&t0, NULL);
int res = modbus_read_registers(ctx, addr, nb, dest);
gettimeofday(&t1, NULL);
long elapsed_us = (t1.tv_sec - t0.tv_sec) * 1000000 + (t1.tv_usec - t0.tv_usec);
if (res < 0) {
const char *error_str = modbus_strerror(errno);
printf("MBUS: modbus_read_registers addr=0x%X nb=%d -> ERR (%s) elapsed=%ldus\n",
addr, nb, error_str, elapsed_us);
if (strstr(error_str, "timeout") || strstr(error_str, "Timed out") || elapsed_us > TIMEOUT_THRESHOLD_US) {
*success = 0; /* Timeout */
return -2;
} else if (strstr(error_str, "CRC") || strstr(error_str, "crc")) {
*success = -1; /* CRC error */
return -1;
} else {
*success = 0; /* Inny błąd */
return 0;
}
} else {
printf("MBUS: modbus_read_registers addr=0x%X nb=%d -> OK (%d) elapsed=%ldus\n",
addr, nb, res, elapsed_us);
*success = 1; /* Sukces */
return elapsed_us;
}
}
/* Test function for ORNO voltage reading */
int test_orno_voltage(modbus_t *ctx, test_results_t *results) {
uint16_t reg[6];
long elapsed_time;
int success_flag;
results->total_time_us = 0;
results->min_time_us = LONG_MAX;
results->max_time_us = 0;
results->successful_reads = 0;
results->total_reads = NUM_READINGS;
results->crc_errors = 0;
results->timeouts = 0;
printf("\n=== TESTING ORNO VOLTAGE READING ===\n");
printf("Performing %d voltage readings...\n", NUM_READINGS);
for (int i = 0; i < NUM_READINGS; i++) {
printf("Reading %d: ", i+1);
elapsed_time = modbus_read_timed(ctx, 0x0e, 6, reg, &success_flag);
if (success_flag == 1) {
/* Poprawny odczyt */
results->total_time_us += elapsed_time;
if (elapsed_time < results->min_time_us) results->min_time_us = elapsed_time;
if (elapsed_time > results->max_time_us) results->max_time_us = elapsed_time;
results->successful_reads++;
float U1 = modbus_get_float_abcd(&reg[0]);
float U2 = modbus_get_float_abcd(&reg[2]);
float U3 = modbus_get_float_abcd(&reg[4]);
printf("Voltages: L1=%.1fV L2=%.1fV L3=%.1fV\n", U1, U2, U3);
} else if (success_flag == -1) {
/* Błąd CRC */
results->crc_errors++;
printf("CRC Error\n");
} else if (success_flag == 0) {
/* Timeout lub inny błąd */
results->timeouts++;
printf("Timeout/Error\n");
}
usleep(10000); // 10ms delay between reads
}
/* Oblicz statystyki tylko dla poprawnych odczytów */
if (results->successful_reads > 0) {
results->avg_time_ms = (double)results->total_time_us / results->successful_reads / 1000.0;
} else {
results->avg_time_ms = 0;
results->min_time_us = 0;
results->max_time_us = 0;
}
return 0;
}
/* Test function for SUN2K voltage reading */
int test_sun2k_voltage(modbus_t *ctx, test_results_t *results) {
uint16_t reg[3];
long elapsed_time;
int success_flag;
results->total_time_us = 0;
results->min_time_us = LONG_MAX;
results->max_time_us = 0;
results->successful_reads = 0;
results->total_reads = NUM_READINGS;
results->crc_errors = 0;
results->timeouts = 0;
printf("\n=== TESTING SUN2K VOLTAGE READING ===\n");
printf("Performing %d voltage readings...\n", NUM_READINGS);
for (int i = 0; i < NUM_READINGS; i++) {
printf("Reading %d: ", i+1);
elapsed_time = modbus_read_timed(ctx, 32069, 3, reg, &success_flag);
if (success_flag == 1) {
/* Poprawny odczyt */
results->total_time_us += elapsed_time;
if (elapsed_time < results->min_time_us) results->min_time_us = elapsed_time;
if (elapsed_time > results->max_time_us) results->max_time_us = elapsed_time;
results->successful_reads++;
float U_A = (float)reg[0] / 10.0;
float U_B = (float)reg[1] / 10.0;
float U_C = (float)reg[2] / 10.0;
printf("Voltages: U_A=%.1fV U_B=%.1fV U_C=%.1fV\n", U_A, U_B, U_C);
} else if (success_flag == -1) {
/* Błąd CRC */
results->crc_errors++;
printf("CRC Error\n");
} else if (success_flag == 0) {
/* Timeout lub inny błąd */
results->timeouts++;
printf("Timeout/Error\n");
}
usleep(10000); // 10ms delay between reads
}
/* Oblicz statystyki tylko dla poprawnych odczytów */
if (results->successful_reads > 0) {
results->avg_time_ms = (double)results->total_time_us / results->successful_reads / 1000.0;
} else {
results->avg_time_ms = 0;
results->min_time_us = 0;
results->max_time_us = 0;
}
return 0;
}
/* Initialize ORNO modbus context */
modbus_t* init_orno_context(const char *device, int slave_addr) {
modbus_t *ctx = modbus_new_rtu(device, 9600, 'E', 8, 1);
if (!ctx) {
fprintf(stderr, "ORNO: Failed to create the context: %s\n", modbus_strerror(errno));
return NULL;
}
modbus_set_slave(ctx, slave_addr);
if (modbus_connect(ctx) == -1) {
fprintf(stderr, "ORNO: Unable to connect: %s\n", modbus_strerror(errno));
modbus_free(ctx);
return NULL;
}
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);
printf("ORNO: Context initialized successfully\n");
return ctx;
}
/* Initialize SUN2K modbus context */
modbus_t* init_sun2k_context(const char *device, int slave_addr) {
modbus_t *ctx = modbus_new_rtu(device, 9600, 'N', 8, 1);
if (!ctx) {
fprintf(stderr, "SUN2K: Failed to create the context: %s\n", modbus_strerror(errno));
return NULL;
}
modbus_set_slave(ctx, slave_addr);
if (modbus_connect(ctx) == -1) {
fprintf(stderr, "SUN2K: Unable to connect: %s\n", modbus_strerror(errno));
modbus_free(ctx);
return NULL;
}
modbus_rtu_set_rts_delay(ctx, SUN2K_RTS_DELAY);
modbus_set_response_timeout(ctx, 0, 900000); /* 0.9s */
modbus_set_byte_timeout(ctx, 0, SUN2K_BYTE_TIMEOUT);
printf("SUN2K: Context initialized successfully\n");
return ctx;
}
/* Print test results */
void print_results(const char *device_name, test_results_t *results) {
printf("\n=== %s TEST RESULTS ===\n", device_name);
printf("Total readings: %d\n", results->total_reads);
printf("Successful readings: %d\n", results->successful_reads);
printf("CRC errors: %d\n", results->crc_errors);
printf("Timeouts/Other errors: %d\n", results->timeouts);
printf("Success rate: %.1f%%\n",
(results->total_reads > 0) ? (100.0 * results->successful_reads / results->total_reads) : 0);
if (results->successful_reads > 0) {
printf("Average time per reading: %.2f ms\n", results->avg_time_ms);
printf("Minimum time: %.2f ms\n", results->min_time_us / 1000.0);
printf("Maximum time: %.2f ms\n", results->max_time_us / 1000.0);
printf("Total time for successful readings: %.2f ms\n", results->total_time_us / 1000.0);
} else {
printf("No successful readings!\n");
}
printf("========================\n\n");
}
/* Compare devices and recommend faster one (based only on successful readings) */
void compare_and_recommend(test_results_t *orno_results, test_results_t *sun2k_results) {
printf("=== COMPARISON AND RECOMMENDATION ===\n");
if (orno_results->successful_reads == 0 && sun2k_results->successful_reads == 0) {
printf("ERROR: Neither device could be read successfully!\n");
return;
}
if (orno_results->successful_reads > 0 && sun2k_results->successful_reads > 0) {
printf("Both devices are working. Comparison:\n");
printf("- ORNO average time: %.2f ms (from %d successful readings)\n",
orno_results->avg_time_ms, orno_results->successful_reads);
printf("- SUN2K average time: %.2f ms (from %d successful readings)\n",
sun2k_results->avg_time_ms, sun2k_results->successful_reads);
if (orno_results->avg_time_ms < sun2k_results->avg_time_ms) {
printf("RECOMMENDATION: ORNO is faster by %.2f ms per reading\n",
sun2k_results->avg_time_ms - orno_results->avg_time_ms);
} else if (sun2k_results->avg_time_ms < orno_results->avg_time_ms) {
printf("RECOMMENDATION: SUN2K is faster by %.2f ms per reading\n",
orno_results->avg_time_ms - sun2k_results->avg_time_ms);
} else {
printf("RECOMMENDATION: Both devices have similar performance\n");
}
} else if (orno_results->successful_reads > 0) {
printf("RECOMMENDATION: Only ORNO has successful readings (%d). Use ORNO for fast voltage readings.\n",
orno_results->successful_reads);
} else if (sun2k_results->successful_reads > 0) {
printf("RECOMMENDATION: Only SUN2K has successful readings (%d). Use SUN2K for fast voltage readings.\n",
sun2k_results->successful_reads);
}
/* Reliability analysis */
printf("\nReliability Analysis:\n");
if (orno_results->crc_errors > 0 || orno_results->timeouts > 0) {
printf("- ORNO had %d CRC errors and %d timeouts\n",
orno_results->crc_errors, orno_results->timeouts);
}
if (sun2k_results->crc_errors > 0 || sun2k_results->timeouts > 0) {
printf("- SUN2K had %d CRC errors and %d timeouts\n",
sun2k_results->crc_errors, sun2k_results->timeouts);
}
if ((orno_results->crc_errors + orno_results->timeouts) > (sun2k_results->crc_errors + sun2k_results->timeouts)) {
printf("RELIABILITY: SUN2K is more reliable\n");
} else if ((orno_results->crc_errors + orno_results->timeouts) < (sun2k_results->crc_errors + sun2k_results->timeouts)) {
printf("RELIABILITY: ORNO is more reliable\n");
} else {
printf("RELIABILITY: Both devices show similar reliability\n");
}
printf("=====================================\n");
}
int main(int argc, char *argv[]) {
const char *USB_DEV = USB_DEV_DEFAULT;
int ORNO_SLAVE = ORNO_SLAVE_ADR;
int SUN2000_SLAVE = SUN2000_SLAVE_ADR;
test_results_t orno_results = {0};
test_results_t sun2k_results = {0};
printf("==============================================\n");
printf("Voltage Reading Speed Test\n");
printf("Testing ORNO vs SUN2K voltage reading speed\n");
printf("==============================================\n");
printf("Configuration:\n");
printf(" Device: %s\n", USB_DEV);
printf(" ORNO slave address: %d\n", ORNO_SLAVE);
printf(" SUN2K slave address: %d\n", SUN2000_SLAVE);
printf(" Number of readings per device: %d\n", NUM_READINGS);
printf("==============================================\n\n");
// Test ORNO
modbus_t *orno_ctx = init_orno_context(USB_DEV, ORNO_SLAVE);
if (orno_ctx) {
test_orno_voltage(orno_ctx, &orno_results);
modbus_close(orno_ctx);
modbus_free(orno_ctx);
} else {
printf("ORNO: Could not initialize context. Skipping ORNO tests.\n");
orno_results.successful_reads = 0;
}
usleep(100000); // 100ms delay between devices
// Test SUN2K
modbus_t *sun2k_ctx = init_sun2k_context(USB_DEV, SUN2000_SLAVE);
if (sun2k_ctx) {
test_sun2k_voltage(sun2k_ctx, &sun2k_results);
modbus_close(sun2k_ctx);
modbus_free(sun2k_ctx);
} else {
printf("SUN2K: Could not initialize context. Skipping SUN2K tests.\n");
sun2k_results.successful_reads = 0;
}
// Print results
if (orno_results.total_reads > 0) {
print_results("ORNO", &orno_results);
}
if (sun2k_results.total_reads > 0) {
print_results("SUN2K", &sun2k_results);
}
// Compare and recommend
compare_and_recommend(&orno_results, &sun2k_results);
printf("\nTest completed.\n");
return 0;
}

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

View File

@@ -0,0 +1 @@
influx delete --host "http://localhost:5086" --org "sic" --bucket "energydb" --token "BCIZ6kcCAVgpcwSfU0PBS7m0Zb6an93kuOtizbEtlXub-uaoYp4dmIQBQYaJCv8_KE4QYYZ08jxtpaZ3TUWP-Q==" --start 1970-01-01T00:00:00Z --stop $(date -u +"%Y-%m-%dT%H:%M:%SZ") --predicate '_fields="highfluct"'