feat: mark Modbus connection loss in InfluxDB
SolarEdge firmware is known to silently drop the Modbus TCP listener (port refuses connections while still shown as enabled). Write a connection_state=1 point on first failed poll and 0 on recovery so the outage is visible in Grafana instead of just a data gap. ConnectionException is re-raised from read() - it is fatal for the whole cycle, not a flaky single block. Marker points carry no tags (registers unreadable during outage), so the tile query skips the serial filter. Also includes threshold tweaks on the power stat tiles.
This commit is contained in:
3 files changed
+128
-2
No files matched your search
+114
-1
@@ -37,6 +37,19 @@
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "text",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "green",
|
||||
"value": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "watt"
|
||||
},
|
||||
"overrides": []
|
||||
@@ -82,6 +95,19 @@
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "red",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "green",
|
||||
"value": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "watt"
|
||||
},
|
||||
"overrides": []
|
||||
@@ -117,7 +143,7 @@
|
||||
"resultFormat": "time_series"
|
||||
}
|
||||
],
|
||||
"title": "Netz aktuell (+ Bezug / - Einspeisung)",
|
||||
"title": "Netz aktuell (+ Einspeisung / - Bezug)",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
@@ -127,6 +153,19 @@
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "watt"
|
||||
},
|
||||
"overrides": []
|
||||
@@ -2818,6 +2857,80 @@
|
||||
],
|
||||
"title": "Temperaturen",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "influxdb",
|
||||
"uid": "${DS_INFLUXDB}"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"mappings": [
|
||||
{
|
||||
"type": "value",
|
||||
"options": {
|
||||
"0": {
|
||||
"text": "OK",
|
||||
"color": "green",
|
||||
"index": 0
|
||||
},
|
||||
"1": {
|
||||
"text": "Verbindung verloren",
|
||||
"color": "red",
|
||||
"index": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 4,
|
||||
"w": 4,
|
||||
"x": 0,
|
||||
"y": 94
|
||||
},
|
||||
"id": 109,
|
||||
"options": {
|
||||
"colorMode": "background",
|
||||
"graphMode": "none",
|
||||
"textMode": "value",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "influxdb",
|
||||
"uid": "${DS_INFLUXDB}"
|
||||
},
|
||||
"query": "SELECT last(\"connection_state\") FROM \"$measurement\" WHERE $timeFilter",
|
||||
"refId": "A",
|
||||
"rawQuery": true,
|
||||
"resultFormat": "time_series"
|
||||
}
|
||||
],
|
||||
"title": "Modbus-Verbindung",
|
||||
"type": "stat"
|
||||
}
|
||||
],
|
||||
"refresh": "1m",
|
||||
|
||||
@@ -81,15 +81,24 @@ if __name__ == '__main__':
|
||||
unit=config['modbus']['unit']
|
||||
)
|
||||
|
||||
modbus_ok = True
|
||||
measurement = config['influx'].get('measurement', 'solaredge')
|
||||
|
||||
while True:
|
||||
try:
|
||||
raw = inverter.read()
|
||||
if not modbus_ok:
|
||||
publish(to_line_protocol({'connection_state': 0}, measurement), config['influx'])
|
||||
modbus_ok = True
|
||||
solar_data = SolarData(raw)
|
||||
line = to_line_protocol(solar_data.data, config['influx'].get('measurement', 'solaredge'))
|
||||
line = to_line_protocol(solar_data.data, measurement)
|
||||
if line:
|
||||
publish(line, config['influx'])
|
||||
except ConnectionException as err:
|
||||
print('Cannot connect to SolarEdge Modbus server on {0}:{1}, error: {2}'.format(
|
||||
config['modbus']['host'], config['modbus']['port'], err))
|
||||
if modbus_ok:
|
||||
publish(to_line_protocol({'connection_state': 1}, measurement), config['influx'])
|
||||
modbus_ok = False
|
||||
|
||||
time.sleep(config['poll_interval'])
|
||||
@@ -3,6 +3,7 @@ import math
|
||||
import time
|
||||
|
||||
from pymodbus.constants import Endian
|
||||
from pymodbus.exceptions import ConnectionException
|
||||
from pymodbus.payload import BinaryPayloadDecoder
|
||||
from pymodbus.client.sync import ModbusTcpClient
|
||||
from pymodbus.client.sync import ModbusSerialClient
|
||||
@@ -322,6 +323,9 @@ class MyInverter:
|
||||
|
||||
data[rname] = self._decode_value(rawData, rlength, dtype, vtype)
|
||||
offset += rlength
|
||||
except ConnectionException:
|
||||
# connection loss is fatal for the whole cycle, not a flaky block
|
||||
raise
|
||||
except Exception as err:
|
||||
print('Modbus block {0} failed, skipping this cycle: {1}'.format(name, err))
|
||||
|
||||
|
||||
Reference in new issue
Block a user