Reading Data from Solaredge inverters via Modbus TCP

And finally, the rules needed to populate the Float items for the Modbus meter.

rule se9km_DID_map
when Item se9km_DID_int received update
then

var String str=“-”
if (se9km_DID_int.state == 201) str = “Einphasig A-N”
if (se9km_DID_int.state == 202) str = “Split single phase A-B-N”
if (se9km_DID_int.state == 203) str = “Dreiphasig Wye (A-B-C-N)”
if (se9km_DID_int.state == 204) str = “Dreiphasig Delta (A-B-C)”

    logDebug("Einspeisepunkt Smartmeter Typ:  ", str)
    postUpdate(se9km_DID, str)

end

rule se9km_Amp_add
when Item se9km_Amp_int received update
then
var Double Amp= (se9km_Amp_int.state as DecimalType).doubleValue
if (Amp > 32767) Amp = Amp-(65536).doubleValue
var Double SF = (se9km_AmpSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = Amp * Math::pow(10,SF)
    var String value = result.toString
    logDebug("Einpseisepunkt Strom phasensaldiert gesamt: ", value)
    postUpdate(se9km_Amp, result)

end

rule se9km_AmpA_add
when Item se9km_AmpA_int received update
then
var Double Amp= (se9km_AmpA_int.state as DecimalType).doubleValue
if (Amp > 32767) Amp = Amp-(65536).doubleValue
var Double SF = (se9km_AmpSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = Amp * Math::pow(10,SF)
  var String value = result.toString
    logDebug("Einspeisepunkt Strom Ph. A: ", value)
    postUpdate(se9km_AmpA, result)

end

rule se9km_AmpB_add
when Item se9km_AmpB_int received update
then
var String str = “http://192.168.199.41:88/middleware.php/data/
var String uuid = “212cde50-ef85-11e6-8115-e7892dde135b.json”
var String operation = “?operation=add&value=”
var Double Amp= (se9km_AmpB_int.state as DecimalType).doubleValue
if (Amp > 32767) Amp = Amp-(65536).doubleValue
var Double SF = (se9km_AmpSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = Amp * Math::pow(10,SF)
    var String value = result.toString
    logDebug("Einspeisepunkt Strom Ph. B: ", value)
    postUpdate(se9km_AmpB, result)

end

rule se9km_AmpC_add
when Item se9km_AmpC_int received update
then
var Double Amp= (se9km_AmpC_int.state as DecimalType).doubleValue
if (Amp > 32767) Amp = Amp-(65536).doubleValue
var Double SF = (se9km_AmpSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = Amp * Math::pow(10,SF)
    var String value = result.toString
    logDebug("Einspeisepunkt Strom Ph. C: ", value)
    postUpdate(se9km_AmpC, result)

end

rule se9km_VoltL_add
when Item se9km_VoltL_int received update
then
var Double Volt= (se9km_VoltL_int.state as DecimalType).doubleValue
if (Volt > 32767) Volt = Volt-(65536).doubleValue
var Double SF = (se9km_VoltSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = Volt * Math::pow(10,SF)
    
    var String value = result.toString
    logDebug("Einpseisepunkt mittlere Spannung: ", value)
    postUpdate(se9km_VoltL, result)

end

rule se9km_VoltA_add
when Item se9km_VoltA_int received update
then
var Double Volt= (se9km_VoltA_int.state as DecimalType).doubleValue
if (Volt > 32767) Volt = Volt-(65536).doubleValue
var Double SF = (se9km_VoltSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = Volt * Math::pow(10,SF)
    var String value = result.toString
    logDebug("Einpseisepunkt Spannung Ph.A: ", value)
    postUpdate(se9km_VoltA, result)

end

rule se9km_VoltB_add
when Item se9km_VoltB_int received update
then
var Double Volt= (se9km_VoltB_int.state as DecimalType).doubleValue
if (Volt > 32767) Volt = Volt-(65536).doubleValue
var Double SF = (se9km_VoltSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = Volt * Math::pow(10,SF)
    var String value = result.toString
    logDebug("Einpseisepunkt Spannung Ph.B: ", value)
    postUpdate(se9km_VoltB, result)

end

rule se9km_VoltC_add
when Item se9km_VoltC_int received update
then
var Double Volt= (se9km_VoltC_int.state as DecimalType).doubleValue
if (Volt > 32767) Volt = Volt-(65536).doubleValue
var Double SF = (se9km_VoltSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = Volt * Math::pow(10,SF)
    var String value = result.toString
    logDebug("Einpseisepunkt Spannung Ph.C: ", value)
    postUpdate(se9km_VoltC, result)

end

rule se9km_Frequenz_add
when Item se9km_Frequenz_int received update
then
var Double Hz= (se9km_Frequenz_int.state as DecimalType).doubleValue
if (Hz > 32767) Hz = Hz-(65536).doubleValue
var Double SF = (se9km_FrequenzSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = Hz * Math::pow(10,SF)
    var String value = result.toString
    logDebug("Einpseisepunkt Netzfrequenz: ", value)
    postUpdate(se9km_Frequenz, result)

end

rule se9km_Watt_add
when Item se9km_Watt_int received update
then

	var Double Watt= (se9km_Watt_int.state as DecimalType).doubleValue
	if (Watt > 32767) Watt = Watt-(65536).doubleValue
	var Double SF = (se9km_WattSF_int.state as DecimalType).doubleValue
    if (SF > 32767) SF = SF-(65536).doubleValue
    var Double result = -1.0 * Watt * Math::pow(10,SF)
  var Double resultplus = 0.0
  var Double resultminus = 0.0
  if (result > 0) {
  	resultplus = result
  } else {
  	resultminus = result
  }
    
    logInfo("[se9km_Watt ]: ", result.toString)
  logInfo("[se9km_Watt+]: ", resultplus.toString)
  logInfo("[se9km_Watt-]: ", resultminus.toString)
    
    postUpdate(se9km_Watt, result)
    postUpdate(se9km_Wattp, resultplus)
    postUpdate(se9km_Wattm, resultminus)

end

rule se9km_WattA_add
when Item se9km_WattA_int received update
then
var Double Watt= (se9km_WattA_int.state as DecimalType).doubleValue
if (Watt > 32767) Watt = Watt-(65536).doubleValue
var Double SF = (se9km_WattSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = -1.0 * Watt * Math::pow(10,SF)
    var String value = result.toString
    logDebug("Einpseisepunkt Wirkleistung Ph.A: ", value)
    postUpdate(se9km_WattA, result)

end

rule se9km_WattB_add
when Item se9km_WattB_int received update
then
var Double Watt= (se9km_WattB_int.state as DecimalType).doubleValue
if (Watt > 32767) Watt = Watt-(65536).doubleValue
var Double SF = (se9km_WattSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = -1.0 * Watt * Math::pow(10,SF)
    var String value = result.toString
    logDebug("Einpseisepunkt Wirkleistung Ph.B: ", value)
    postUpdate(se9km_WattB, result)

end

rule se9km_WattC_add
when Item se9km_WattC_int received update
then
var Double Watt= (se9km_WattC_int.state as DecimalType).doubleValue
if (Watt > 32767) Watt = Watt-(65536).doubleValue
var Double SF = (se9km_WattSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = -1.0 * Watt * Math::pow(10,SF)
    var String value = result.toString
    logDebug("Einpseisepunkt Wirkleistung Ph.C: ", value)
    postUpdate(se9km_WattC, result)

end

rule se9km_VA_add
when Item se9km_VA_int received update
then
var Double VA= (se9km_VA_int.state as DecimalType).doubleValue
if (VA > 32767) VA = VA-(65536).doubleValue
var Double SF = (se9km_VASF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = VA * Math::pow(10,SF)
    var String value = result.toString
    logDebug("Einpseisepunkt Scheinleistung Summe: ", value)
    postUpdate(se9km_VA, result)

end

rule se9km_VAA_add
when Item se9km_VAA_int received update
then
var Double VA= (se9km_VAA_int.state as DecimalType).doubleValue
if (VA > 32767) VA = VA-(65536).doubleValue
var Double SF = (se9km_VASF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = VA * Math::pow(10,SF)
    var String value = result.toString
    logDebug("Einpseisepunkt Scheinleistung Ph.A: ", value)
    postUpdate(se9km_VAA, result)

end

rule se9km_VAB_add
when Item se9km_VAB_int received update
then
var Double VA= (se9km_VAB_int.state as DecimalType).doubleValue
if (VA > 32767) VA = VA-(65536).doubleValue
var Double SF = (se9km_VASF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = VA * Math::pow(10,SF)
    var String value = result.toString
    logDebug("Einpseisepunkt Scheinleistung Ph.B: ", value)
    postUpdate(se9km_VAB, result)

end

rule se9km_VAC_add
when Item se9km_VAC_int received update
then
var Double VA= (se9km_VAC_int.state as DecimalType).doubleValue
if (VA > 32767) VA = VA-(65536).doubleValue
var Double SF = (se9km_VASF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = VA * Math::pow(10,SF)
    var String value = result.toString
    logDebug("Einpseisepunkt Scheinleistung Ph.C: ", value)
    postUpdate(se9km_VAC, result)

end

rule se9km_VAR_add
when Item se9km_VAR_int received update
then
var Double VAR= (se9km_VAR_int.state as DecimalType).doubleValue
if (VAR > 32767) VAR = VAR-(65536).doubleValue
var Double SF = (se9km_VARSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = VAR * Math::pow(10,SF)
    var String value = result.toString
    logDebug("Einpseisepunkt reaktive Leistung (Summe): ", value)
    postUpdate(se9km_VAR, result)

end

rule se9km_VARA_add
when Item se9km_VARA_int received update
then
var Double VAR= (se9km_VARA_int.state as DecimalType).doubleValue
if (VAR > 32767) VAR = VAR-(65536).doubleValue
var Double SF = (se9km_VARSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = VAR * Math::pow(10,SF)
    var String value = result.toString
    logDebug("Einpseisepunkt reaktive Leistung Ph.A: ", value)
    postUpdate(se9km_VARA, result)

end

rule se9km_VARB_add
when Item se9km_VARB_int received update
then
var Double VAR= (se9km_VARB_int.state as DecimalType).doubleValue
if (VAR > 32767) VAR = VAR-(65536).doubleValue
var Double SF = (se9km_VARSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = VAR * Math::pow(10,SF)
    var String value = result.toString
    logDebug("Einpseisepunkt reaktive Leistung Ph.B: ", value)
    postUpdate(se9km_VARB, result)

end

rule se9km_VARC_add
when Item se9km_VARC_int received update
then
var Double VAR= (se9km_VARC_int.state as DecimalType).doubleValue
if (VAR > 32767) VAR = VAR-(65536).doubleValue
var Double SF = (se9km_VARSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = VAR * Math::pow(10,SF)
    var String value = result.toString
    logDebug("Einpseisepunkt reaktive Leistung Ph.C: ", value)
    postUpdate(se9km_VARC, result)

end

rule se9km_PF_add
when Item se9km_PF_int received update
then
var Double PF= (se9km_PF_int.state as DecimalType).doubleValue
if (PF > 32767) PF = PF-(65536).doubleValue
var Double SF = (se9km_PFSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = PF * Math::pow(10,SF) /100
    var String value = result.toString
    logDebug("Einpseisepunkt Leistungsfaktor MW: ", value)
    postUpdate(se9km_PF, result)

end

rule se9km_PFA_add
when Item se9km_PFA_int received update
then
var Double PF= (se9km_PFA_int.state as DecimalType).doubleValue
if (PF > 32767) PF = PF-(65536).doubleValue
var Double SF = (se9km_PFSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = PF * Math::pow(10,SF) /100
    var String value = result.toString
    logDebug("Einpseisepunkt Leistungsfaktor Ph.A: ", value)
    postUpdate(se9km_PFA, result)

end

rule se9km_PFB_add
when Item se9km_PFB_int received update
then
var Double PF= (se9km_PFB_int.state as DecimalType).doubleValue
if (PF > 32767) PF = PF-(65536).doubleValue
var Double SF = (se9km_PFSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = PF * Math::pow(10,SF) /100
    var String value = result.toString
    logDebug("Einpseisepunkt Leistungsfaktor Ph.B: ", value)
    postUpdate(se9km_PFB, result)

end

rule se9km_PFC_add
when Item se9km_PFC_int received update
then
var Double PF= (se9km_PFC_int.state as DecimalType).doubleValue
if (PF > 32767) PF = PF-(65536).doubleValue
var Double SF = (se9km_PFSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = PF * Math::pow(10,SF) /100
    var String value = result.toString
    logDebug("Einpseisepunkt Leistungsfaktor Ph.C: ", value)
    postUpdate(se9km_PFC, result)

end

rule se9km_kWh_Exp_add
when Item se9km_Wh2_Exp_int received update

then
var Double SF = (se9km_WhSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double resultWh = ((se9km_Wh1_Exp_int.state as DecimalType * 65536).doubleValue + (se9km_Wh2_Exp_int.state as DecimalType).doubleValue) * Math::pow(10,SF)
  var Double resultnegWh = 1000000000 - resultWh
    var Double Offset = (se9km_kWh_Exp_Jahr_Offset.state as DecimalType).doubleValue * 1000.0
    var Double Jahr = (resultWh - Offset) / 1000.0
  var String valueWh = resultWh.toString
  var String valuenegWh = resultnegWh.toString
    var String wrjahr = Jahr.toString
  logInfo("[se9km_Exp      ]  Wh: ",valueWh)
  logInfo("[se9km_Exp (neg)]  Wh: ",valuenegWh)
    logInfo("[se9km_Exp Jahr ] kWh: ", wrjahr)
  var Double result = resultWh / 1000.0
  var Double resultneg = resultnegWh / 1000.0
    postUpdate(se9km_kWh_Exp, result)
    postUpdate(se9km_kWh_Exp_Jahr, Jahr)
    postUpdate(se9km_kWh_Exp_neg, resultneg)

end

rule se9km_kWhA_Exp_add
when Item se9km_WhA2_Exp_int received update

then
var Double SF = (se9km_WhSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = ((se9km_WhA1_Exp_int.state as DecimalType *65536).doubleValue + (se9km_WhA2_Exp_int.state as DecimalType).doubleValue) * Math::pow(10,SF) / 1000.0 
    var String value = result.toString
    logDebug("Einspeisezaehler Ph.A kWh: ", value)
    postUpdate(se9km_kWhA_Exp, result)

end

rule se9km_kWhB_Exp_add
when Item se9km_WhB2_Exp_int received update
then
var Double SF = (se9km_WhSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = ((se9km_WhB1_Exp_int.state as DecimalType * 65536).doubleValue + (se9km_WhB2_Exp_int.state as DecimalType).doubleValue) * Math::pow(10,SF) / 1000.0 
    var String value = result.toString
    logDebug("Einspeisezaehler Ph.B kWh: ", value)
    postUpdate(se9km_kWhB_Exp, result)

end

rule se9km_kWhC_Exp_add
when Item se9km_WhC2_Exp_int received update
then
var Double SF = (se9km_WhSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = ((se9km_WhC1_Exp_int.state as DecimalType * 65536).doubleValue + (se9km_WhC2_Exp_int.state as DecimalType).doubleValue) * Math::pow(10,SF) / 1000.0 
    var String value = result.toString
    logDebug("Einspeisezaehler Ph.C kWh: ", value)
    postUpdate(se9km_kWhC_Exp, result)

end

rule se9km_kWh_Imp_add
when Item se9km_Wh2_Imp_int received update
then
var Double SF = (se9km_WhSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double resultWh = ((se9km_Wh1_Imp_int.state as DecimalType * 65536).doubleValue + (se9km_Wh2_Imp_int.state as DecimalType).doubleValue) * Math::pow(10,SF)
    var Double Offset = (se9km_kWh_Imp_Jahr_Offset.state as DecimalType).doubleValue * 1000.0
    var Double Jahr = (resultWh - Offset) / 1000.0
  var String valueWh = resultWh.toString
  var String urlWh = str + uuidWh + operation + valueWh
    var String wrjahr = Jahr.toString
  logInfo("[se9km_Imp]  Wh: ", valueWh)
    logInfo("[se9km_Imp Jahr] kWh: ", wrjahr)
  var Double result = resultWh / 1000.0
    postUpdate(se9km_kWh_Imp, result)
    postUpdate(se9km_kWh_Imp_Jahr, Jahr)

end

rule se9km_kWhA_Imp_add
when Item se9km_WhA2_Imp_int received update
then
var Double SF = (se9km_WhSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = ((se9km_WhA1_Imp_int.state as DecimalType * 65536).doubleValue + (se9km_WhA2_Imp_int.state as DecimalType).doubleValue) * Math::pow(10,SF) / 1000.0 

    var String value = result.toString
    logDebug("Bezugszaehler Ph.A kWh: ", value)
    postUpdate(se9km_kWhA_Imp, result)

end

rule se9km_kWhB_Imp_add
when Item se9km_WhB2_Imp_int received update
then
var Double SF = (se9km_WhSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = ((se9km_WhB1_Imp_int.state as DecimalType * 65536).doubleValue + (se9km_WhB2_Imp_int.state as DecimalType).doubleValue) * Math::pow(10,SF) / 1000.0 

    var String value = result.toString
    logDebug("Bezugszaehler Ph.B kWh: ", value)
    postUpdate(se9km_kWhB_Imp, result)

end

rule se9km_kWhC_Imp_add
when Item se9km_WhC2_Imp_int received update
then
var Double SF = (se9km_WhSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = ((se9km_WhC1_Imp_int.state as DecimalType * 65536).doubleValue + (se9km_WhC2_Imp_int.state as DecimalType).doubleValue) * Math::pow(10,SF) / 1000.0 
    var String value = result.toString
    logDebug("Bezugszaehler Ph.C kWh: ", value)
    postUpdate(se9km_kWhC_Imp, result)

end

rule se9km_VAh_Exp_add
when Item se9km_VAh2_Exp_int received update
then
var Double SF = (se9km_VAhSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = ((se9km_VAh1_Exp_int.state as DecimalType * 65536).doubleValue + (se9km_VAh2_Exp_int.state as DecimalType).doubleValue) * Math::pow(10,SF) / 1000.0 

    var String value = result.toString
    logDebug("Einspeisezaehler Scheinleistung (Summe) kVAh: ", value)
    postUpdate(se9km_VAh_Exp, result)

end

rule se9km_VAhA_Exp_add
when Item se9km_VAhA2_Exp_int received update
then
var Double SF = (se9km_VAhSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = ((se9km_VAhA1_Exp_int.state as DecimalType * 65536).doubleValue + (se9km_VAhA2_Exp_int.state as DecimalType).doubleValue) * Math::pow(10,SF) / 1000.0 

    var String value = result.toString
    logDebug("Einspeisezaehler Scheinleistung Ph.A kVAh: ", value
    postUpdate(se9km_VAhA_Exp, result)

end

rule se9km_VAhB_Exp_add
when Item se9km_VAhB2_Exp_int received update
then
var Double SF = (se9km_VAhSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = ((se9km_VAhB1_Exp_int.state as DecimalType * 65536).doubleValue + (se9km_VAhB2_Exp_int.state as DecimalType).doubleValue) * Math::pow(10,SF) / 1000.0 

    var String value = result.toString
    logDebug("Einspeisezaehler Scheinleistung Ph.B kVAh: ", value
    postUpdate(se9km_VAhB_Exp, result)

end

rule se9km_VAhC_Exp_add
when Item se9km_VAhC2_Exp_int received update
then
var Double SF = (se9km_VAhSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = ((se9km_VAhC1_Exp_int.state as DecimalType * 65536).doubleValue + (se9km_VAhC2_Exp_int.state as DecimalType).doubleValue) * Math::pow(10,SF) / 1000.0 

    var String value = result.toString
    logDebug("Einspeisezaehler Scheinleistung Ph.C kVAh: ", value
    postUpdate(se9km_VAhC_Exp, result)

end

rule se9km_VAh_Imp_add
when Item se9km_VAh2_Imp_int received update
then
var Double SF = (se9km_VAhSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = ((se9km_VAh1_Imp_int.state as DecimalType * 65536).doubleValue + (se9km_VAh2_Imp_int.state as DecimalType).doubleValue) * Math::pow(10,SF) / 1000.0 

    var String value = result.toString
    logDebug("Bezugszaehler Scheinleistung (Summe) kVAh: ", value
    postUpdate(se9km_VAh_Imp, result)

end

rule se9km_VAhA_Imp_add
when Item se9km_VAhA2_Imp_int received update
then
var Double SF = (se9km_VAhSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = ((se9km_VAhA1_Imp_int.state as DecimalType * 65536).doubleValue + (se9km_VAhA2_Imp_int.state as DecimalType).doubleValue) * Math::pow(10,SF) / 1000.0 
    var String value = result.toString
    logDebug("Bezugszaehler Scheinleistung Ph.A kVAh: ", value
    postUpdate(se9km_VAhA_Imp, result)

end

rule se9km_VAhB_Imp_add
when Item se9km_VAhB2_Imp_int received update
then
var Double SF = (se9km_VAhSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = ((se9km_VAhB1_Imp_int.state as DecimalType * 65536).doubleValue + (se9km_VAhB2_Imp_int.state as DecimalType).doubleValue) * Math::pow(10,SF) / 1000.0 
    var String value = result.toString
    logDebug("Bezugszaehler Scheinleistung Ph.B kVAh: ", value)
    postUpdate(se9km_VAhB_Imp, result)

end

rule se9km_VAhC_Imp_add
when Item se9km_VAhC2_Imp_int received update
then
var Double SF = (se9km_VAhSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = ((se9km_VAhC1_Imp_int.state as DecimalType * 65536).doubleValue + (se9km_VAhC2_Imp_int.state as DecimalType).doubleValue) * Math::pow(10,SF) / 1000.0 
    var String value = result.toString
    logDebug("Bezugszaehler Scheinleistung Ph.C kVAh: ", value
    postUpdate(se9km_VAhC_Imp, result)

end

rule se9km_VARhQ1_add
when Item se9km_VARhQ12_int received update
then
var Double SF = (se9km_VARhSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = ((se9km_VARhQ11_int.state as DecimalType * 65536).doubleValue + (se9km_VARhQ12_int.state as DecimalType).doubleValue) * Math::pow(10,SF) / 1000.0 
    var String value = result.toString
    logDebug("Bezugszaehler Q1 reaktive Energie (Summe) kWh: ", value
    postUpdate(se9km_VARhQ1, result)

end

rule se9km_VARhQ1A_add
when Item se9km_VARhQ1A2_int received update
then
var Double SF = (se9km_VARhSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = ((se9km_VARhQ1A1_int.state as DecimalType * 65536).doubleValue + (se9km_VARhQ1A2_int.state as DecimalType).doubleValue) * Math::pow(10,SF) / 1000.0 
    var String value = result.toString
    logDebug("Bezugszaehler Q1 reaktive Energie Ph.A kVARh: ", value
    postUpdate(se9km_VARhQ1A, result)

end

rule se9km_VARhQ1B_add
when Item se9km_VARhQ1B2_int received update
then
var Double SF = (se9km_VARhSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = ((se9km_VARhQ1B1_int.state as DecimalType * 65536).doubleValue + (se9km_VARhQ1B2_int.state as DecimalType).doubleValue) * Math::pow(10,SF) / 1000.0 
    var String value = result.toString
    logDebug("Bezugszaehler Q1 reaktive Energie Ph.B kVARh: ", value
    postUpdate(se9km_VARhQ1B, result)

end

rule se9km_VARhQ1C_add
when Item se9km_VARhQ1C2_int received update
then
var Double SF = (se9km_VARhSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = ((se9km_VARhQ1C1_int.state as DecimalType * 65536).doubleValue + (se9km_VARhQ1C2_int.state as DecimalType).doubleValue) * Math::pow(10,SF) / 1000.0 
    var String value = result.toString
    logDebug("Bezugszaehler Q1 reaktive Energie Ph.C kVARh: ", value
    postUpdate(se9km_VARhQ1C, result)

end

rule se9km_VARhQ2_add
when Item se9km_VARhQ22_int received update
then
var Double SF = (se9km_VARhSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = ((se9km_VARhQ21_int.state as DecimalType * 65536).doubleValue + (se9km_VARhQ22_int.state as DecimalType).doubleValue) * Math::pow(10,SF) / 1000.0 
    var String value = result.toString
    logDebug("Bezugszaehler Q2 reaktive Energie (Summe) kVARh: ", value)
    postUpdate(se9km_VARhQ2, result)

end

rule se9km_VARhQ2A_add
when Item se9km_VARhQ2A2_int received update
then
var Double SF = (se9km_VARhSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = ((se9km_VARhQ2A1_int.state as DecimalType * 65536).doubleValue + (se9km_VARhQ2A2_int.state as DecimalType).doubleValue) * Math::pow(10,SF) / 1000.0 
    var String value = result.toString
    logDebug("Bezugszaehler Q2 reaktive Energie Ph.A kVARh: ", value)
    postUpdate(se9km_VARhQ2A, result)

end

rule se9km_VARhQ2B_add
when Item se9km_VARhQ2B2_int received update
then
var Double SF = (se9km_VARhSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = ((se9km_VARhQ2B1_int.state as DecimalType * 65536).doubleValue + (se9km_VARhQ2B2_int.state as DecimalType).doubleValue) * Math::pow(10,SF) / 1000.0 
    var String value = result.toString
    logDebug("Bezugszaehler Q2 reaktive Energie Ph.B kVARh: ", value)
    postUpdate(se9km_VARhQ2B, result)

end

rule se9km_VARhQ2C_add
when Item se9km_VARhQ2C2_int received update
then
var Double SF = (se9km_VARhSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = ((se9km_VARhQ2C1_int.state as DecimalType * 65536).doubleValue + (se9km_VARhQ2C2_int.state as DecimalType).doubleValue) * Math::pow(10,SF) / 1000.0 
    var String value = result.toString
    logDebug("Bezugszaehler Q2 reaktive Energie Ph.C kVARh: ", value)
    postUpdate(se9km_VARhQ2C, result)

end

rule se9km_VARhQ3_add
when Item se9km_VARhQ32_int received update
then
var Double SF = (se9km_VARhSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = ((se9km_VARhQ31_int.state as DecimalType * 65536).doubleValue + (se9km_VARhQ32_int.state as DecimalType).doubleValue) * Math::pow(10,SF) / 1000.0 
    var String value = result.toString
    logDebug("Einspeisezaehler Q3 reaktive Energie (Summe) kVARh: ", value)
    postUpdate(se9km_VARhQ3, result)

end

rule se9km_VARhQ3A_add
when Item se9km_VARhQ3A2_int received update
then
var Double SF = (se9km_VARhSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = ((se9km_VARhQ3A1_int.state as DecimalType * 65536).doubleValue + (se9km_VARhQ3A2_int.state as DecimalType).doubleValue) * Math::pow(10,SF) / 1000.0 
    var String value = result.toString
    logDebug("Einspeisezaehler Q3 reaktive Energie Ph.A kVARh: ", value)
    postUpdate(se9km_VARhQ3A, result)

end

rule se9km_VARhQ3B_add
when Item se9km_VARhQ3B2_int received update
then
var Double SF = (se9km_VARhSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = ((se9km_VARhQ3B1_int.state as DecimalType * 65536).doubleValue + (se9km_VARhQ3B2_int.state as DecimalType).doubleValue) * Math::pow(10,SF) / 1000.0 
    var String value = result.toString
    logDebug("Einspeisezaehler Q3 reaktive Energie Ph.B kVARh: ", value)
    postUpdate(se9km_VARhQ3B, result)

end

rule se9km_VARhQ3C_add
when Item se9km_VARhQ3C2_int received update
then
var Double SF = (se9km_VARhSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = ((se9km_VARhQ3C1_int.state as DecimalType * 65536).doubleValue + (se9km_VARhQ3C2_int.state as DecimalType).doubleValue) * Math::pow(10,SF) / 1000.0 
    var String value = result.toString
    logDebug("Einspeisezaehler Q3 reaktive Energie Ph.C kVARh: ", value)
    postUpdate(se9km_VARhQ3C, result)

end

rule se9km_VARhQ4_add
when Item se9km_VARhQ42_int received update
then
var Double SF = (se9km_VARhSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = ((se9km_VARhQ41_int.state as DecimalType * 65536).doubleValue + (se9km_VARhQ42_int.state as DecimalType).doubleValue) * Math::pow(10,SF) / 1000.0 
    var String value = result.toString
    logDebug("Einspeisezaehler Q4 reaktive Energie (Summe) kVARh: ", value)
    postUpdate(se9km_VARhQ4, result)

end

rule se9km_VARhQ4A_add
when Item se9km_VARhQ4A2_int received update
then
var Double SF = (se9km_VARhSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = ((se9km_VARhQ4A1_int.state as DecimalType * 65536).doubleValue + (se9km_VARhQ4A2_int.state as DecimalType).doubleValue) * Math::pow(10,SF) / 1000.0 
    var String value = result.toString
    logDebug("Einspeisezaehler Q4 reaktive Energie Ph.A kVARh: ", value)
    postUpdate(se9km_VARhQ4A, result)

end

rule se9km_VARhQ4B_add
when Item se9km_VARhQ4B2_int received update
then
var Double SF = (se9km_VARhSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = ((se9km_VARhQ4B1_int.state as DecimalType * 65536).doubleValue + (se9km_VARhQ4B2_int.state as DecimalType).doubleValue) * Math::pow(10,SF) / 1000.0 
    var String value = result.toString
    logDebug("Einspeisezaehler Q4 reaktive Energie Ph.B kVARh: ", value)
    postUpdate(se9km_VARhQ4B, result)

end

rule se9km_VARhQ4C_add
when Item se9km_VARhQ4C2_int received update
then
var Double SF = (se9km_VARhSF_int.state as DecimalType).doubleValue
if (SF > 32767) SF = SF-(65536).doubleValue

    var Double result = ((se9km_VARhQ4C1_int.state as DecimalType * 65536).doubleValue + (se9km_VARhQ4C2_int.state as DecimalType).doubleValue) * Math::pow(10,SF) / 1000.0 
    var String value = result.toString
    logDebug("Einspeisezaehler Q4 reaktive Energie Ph.C kVARh: ", value)
    postUpdate(se9km_VARhQ4C, result)

end

1 Like

Please note that the binding actually opens only single connection, even in the case of many “slaves” in the config. Each slave definition maps to single modbus request.

Even better, the extended item syntax in binding 1.10.0 (see docs here http://docs.openhab.org/addons/bindings/modbus1/readme.html#extended-format) allows you to override valuetype per item.

Perhaps you can simplify the rules using this functionality?

Best
Sami

Hello Sami,

yes I am aware and I did run a number of tests with multiple slaves and a lot of timings. Initially, I had three slaves, one for each valuetype. However it seems that the inverter needs quite a bit of time to recover from read requests and I was not able to get a working config that had more that this minimal number of slaves.

Cheers,

Thomas

Ok that makes then! I think I misunderstood your first post then.

As said, you can use the 1.10.0 functionality to set valuetype per each item separately. If you have single slave, only single request is Sent.

However, I noticed the 32 bit types read from n’th item (first register index would be ((slave start) + (read index)*2)) which means that it’s not applicable to all situations (e.g. When you would like to read 32bit type offsetted by one register).

And transformations are not useful when the transformation should use information from many registers.

So yeah, I think you are right, it does not get much simpler than that.

Sami

Here’s a nice graph of all the data that we have been reading (plus some derived values, such as the directly consumed energy in the house) from a really sunny day.
You can also see where the logic triggers the heatpump to produce some extra hot water with all the nice free energy from the sun.
The graphs are generated using the volkszaehler.org metering application. In my rules, I have some code to feed the data that we read from the inverter to the volkszaehler middleware API. I guess you could also us InfluxDB persistence and feed the data to grafana to produce similar results, but I like the volkszaehler since it is specifically designed to handle meter data.

There are some useful items that you might want to calculate once you have production, export and import power value available, such as:

Directly used energy in your house (“Eigenverbrauch” in german):

Eigenverbrauch = Production - Export

The total used power in your house:

Total = Production + Import - Export

(take care, since Export might be a negative value, so this might actually be Production + Import + Export in that case)

The fraction of the produced solar energy that you use directly in the house without feeding it to the grid (“Eigenverbrauchsanteil” in german):

Eigenverbrauchsanteil = Directly used energy / total production

The part of your total energy usage that you were able to cover by your solar power plant (“Solarer Deckungsgrad” in german):

Solarer Deckungsgrad = Eigenverbrauch / Total used power

Here’s some rules I set up for this (again, sorry for the german item names, I hope you can figure it out):

// Eigenverbrauch (Direktverbrauch) = Erzeugung - Einspeisung
rule se9km_Eigenverbrauch_add
when
Item se9k_kWh received update

then

    var Double result = (se9k_kWh.state as DecimalType).doubleValue - (se9km_kWh_Exp.state as DecimalType).doubleValue
    var String value = result.toString
    logDebug("Eigenverbrauchszaehler kWh: ", value)
    postUpdate(se9km_kWh_Eigen, result)

end

rule se9km_Eigenverbrauchsanteil_Jahr_add
when
Item se9km_kWh_Eigen_Jahr received update

then

    var Double result = (se9km_kWh_Eigen_Jahr.state as DecimalType).doubleValue / (se9k_kWh_Jahr.state as DecimalType).doubleValue * 100.0
    var String value = result.toString
    logDebug("Eigenverbrauchsanteil Jahr: ", value)
    postUpdate(se9km_Eigenanteil_Jahr, result)

end

//Gesamtverbrauch = Eigenverbrauch + Bezug
// = Erzeugung - Einspeisung + Bezug
rule se9km_Gesamtverbrauch_add
when
Item se9km_kWh_Imp received update

then
var Double result = (se9km_kWh_Imp.state as DecimalType).doubleValue + (se9k_kWh.state as DecimalType).doubleValue - (se9km_kWh_Exp.state as DecimalType).doubleValue

    var String value = result.toString
    logDebug("Gesamtverbrauchszaehler Haus kWh: ", value)
    postUpdate(se9km_kWh_Gesamtverbrauch, result)

end

// solarer Deckungsgrad = Eigenverbrauch / Gesamtverbrauch
rule se9km_SolDeckung_add
when
Item se9km_kWh_Eigen received update
or
Item se9km_kWh_Gesamtverbrauch received update

then

    var Double result = (se9km_kWh_Eigen.state as DecimalType).doubleValue / (se9km_kWh_Gesamtverbrauch.state as DecimalType).doubleValue  * 100.0
    var String value = result.toString
    logDebug("solare Deckung: ", value)
    postUpdate(se9km_SolDeckung, result)

end

All the values above use energy meter values rather than power values. These are good to keep track of the total energy values over a longer period of time. However, I found that due to the limited resolution of these values, you will sometimes see jumps in your power graphs. To visualize data (i.e. the nice power graph of the previous post, I usually don’t use energy meter values, but rather I use power values. Here’s a rule that will generate all those derived values and put them into some items:

rule “Update Zaehler und abgeleitete Zaehler”
when Item se9km_Watt received update
then
var Double erzeugung = (se9k_Watt.state as DecimalType).doubleValue
// gridpower = bezug - einspeisung
var Double gridpower = (se9km_Watt.state as DecimalType).doubleValue
var Double verbrauch = erzeugung + gridpower
// Direktverbrauch = Erzeugung - Einspeisung
var Double direktverbrauch = 0.0
// Watthaus = Gesamtverbrauch Haus (Erzeugung + Bezug + Einspeisung)
sendCommand(se9km_WattHaus,verbrauch)

    if (gridpower < 0.0) {
                    direktverbrauch = erzeugung + gridpower
    } else if (gridpower > 0.0) {
                    direktverbrauch = erzeugung
    }
            sendCommand(se9km_direkt,direktverbrauch)
            var String valuedirekt = direktverbrauch.toString
        logInfo("[se9km_WattHaus: ]", valueWattHaus.toString)
            logInfo("[se9km_direkt: ]", valuedirekt.toString)

end

From your experience: Is this going to work with any sun spec implementing inverter? It would be really nice if I could concentrate on the special rules for my heatpump (systemair) instead of replicating all the stuff for Fronius symo inverters.

Thanks

Thomas
(http://www.fronius.com/cps/rde/xchg/SID-2FCEEEAF-3476C114/fronius_international/hs.xsl/83_33732_DEU_HTML.htm#.WOzm3kdCShc)

I guess the answer is “it depends”. Apparently Fronius implements two type of sunpec register maps, one for float and one for integer + scale factors. If your inverter does Integer + scale factors, you should be good with my code. Browsing briefly through the documentation on the Fronius Website, it seems that you should be able to configure the inverter for float oder integer + scale factors to your liking. It also seems that you might need to adjust the Modbus ID in the slave definition to match your inverter and smartmeter if present.

BR,

Thomas

Hello Thomas
Thank you very much, great work! I just could copy and paste !
Do you have also the “code” for the data to push to volkszähler ?

Michael

Sure, the principle is pretty easy. In those rules where you calculate the float values, just add a bit of code to push data into the volkszaehler using it’s API.

The URL is like: “http://ip-address/middleware.php/data/uuid.json?operation=add&value=value

The uuid is the uuid of an existing channel in the volkszaehler (just add one of the correct type using the frontend).

A bit of code to add at the end of each rule would look like this:

        var String str = "http://<ip>/middleware.php/data/"
        var String uuid = "<uuid>.json"
        var String operation = "?operation=add&value="
        var String value = result.toString
        var String url = str + uuid + operation + value
        sendHttpGetRequest(url)

Assuming that the variable “result” holds the value that you want to add.

Cheers,

Thomas

Hi @miesi1,

I have a working config which polls most of the data from a Fronius inverter if you need it.

Brent

I would love to see it documented for the community in rhis section :sunglasses:

The items could probably use some tidying up - I did this a while ago in OpenHAB 1.x which I stopped using then recently converted it to OH2. Unlike in the above example- I was able to use mutiple poll requests, so used a separate poll for each block of contiguous data. This may not be the most efficient, but it works.

modbus.cfg

#Separate connection blocks required for different register type polls
poll=2000

tcp.FroniusBlk1.connection=192.168.21.202:502
tcp.FroniusBlk1.id=1
tcp.FroniusBlk1.start=213
tcp.FroniusBlk1.length=1
tcp.FroniusBlk1.type=holding
tcp.FroniusBlk1.valuetype=uint16

tcp.FroniusBlk2.connection=192.168.21.202:502
tcp.FroniusBlk2.id=1
tcp.FroniusBlk2.start=499
tcp.FroniusBlk2.length=14
tcp.FroniusBlk2.type=holding
tcp.FroniusBlk2.valuetype=uint32

tcp.FroniusBlk3.connection=192.168.21.202:502
tcp.FroniusBlk3.id=1
tcp.FroniusBlk3.start=40071
tcp.FroniusBlk3.length=22
tcp.FroniusBlk3.type=holding
tcp.FroniusBlk3.valuetype=float32

tcp.FroniusBlk4.connection=192.168.21.202:502
tcp.FroniusBlk4.id=1
tcp.FroniusBlk4.start=40091
tcp.FroniusBlk4.length=20
tcp.FroniusBlk4.type=holding
tcp.FroniusBlk4.valuetype=float32

tcp.FroniusBlk5.connection=192.168.21.202:502
tcp.FroniusBlk5.id=1
tcp.FroniusBlk5.start=40117
tcp.FroniusBlk5.length=1
tcp.FroniusBlk5.type=holding
tcp.FroniusBlk5.valuetype=uint16

tcp.FroniusBlk6.connection=192.168.21.202:502
tcp.FroniusBlk6.id=1
tcp.FroniusBlk6.start=40123
tcp.FroniusBlk6.length=8
tcp.FroniusBlk6.type=holding
tcp.FroniusBlk6.valuetype=uint32

tcp.FroniusBlk7.connection=192.168.21.202:502
tcp.FroniusBlk7.id=1
tcp.FroniusBlk7.start=40281
tcp.FroniusBlk7.length=31
tcp.FroniusBlk7.type=holding
tcp.FroniusBlk7.valuetype=uint16

items

Group 	gMyOpenHab
Group 	gSolar
Group	gSolarMain	(gSolar)
Group 	gSolarPower	(gSolar)
Group 	gSolarAC		(gSolar)		
Group 	gSolarDC		(gSolar)
Group	gSolarInfo	(gSolar)
/* Solar 
Number  Solar_Active_StateCode   "Current State [%d]"                  (gSolarMain) {modbus="FroniusBlk1:0"}

Number  Solar_Site_Power         	"Actual Power [%d W]"                  (gSolarMain, gSolarPower) {modbus="FroniusBlk2:0"}
//Number  Solar_Site_Energy_Day_HW 	"Generated Today HW [%d Wh]"         (gSolarMain, gSolarPower) {modbus="FroniusBlk2:1"}
Number  Solar_Site_Energy_Day 		"Generated Today [%d Wh]"            (gSolarMain, gSolarPower) {modbus="FroniusBlk2:2"}
//Number  Solar_F_Site_Energy_Year_HW "Generated Year HW [%d Wh]"      (gSolarPower) {modbus="FroniusBlk2:3"}
Number  Solar_F_Site_Energy_Year_LW "Generated Year  [%d Wh]"          (gSolarPower) {modbus="FroniusBlk2:4"}
//Number  Solar_F_Site_Energy_Tot_HW"Generated Lifetime HW [%d Wh]"        (gSolarPower) {modbus="FroniusBlk2:5"}
Number  Solar_F_Site_Energy_Tot_LW	"Generated Lifetime [%d Wh]"        (gSolarPower) {modbus="FroniusBlk2:6"}

Number  Solar_AC_Current         "AC total current [%.2f A]"               (gSolarAC) {modbus="FroniusBlk3:0"}
Number  Solar_AphA               "AC phase A current [%.2f A]"            (gSolarAC) {modbus="FroniusBlk3:1"}
Number  Solar_AphB               "AC phase B current [%.2f  A]"            (gSolarAC) {modbus="FroniusBlk3:2"}
Number  Solar_AphC               "AC phase C current [%.2f  A]"            (gSolarAC) {modbus="FroniusBlk3:3"}
Number  Solar_PPVphBC            "AC voltage phase BC [%.2f V]"           (gSolarAC) {modbus="FroniusBlk3:5"}
Number  Solar_PPVphCA            "AC voltage phase CA [%.2f V]"           (gSolarAC) {modbus="FroniusBlk3:6"}
Number  Solar_PPVphAB            "AC voltage phase AB [%.2f V]"           (gSolarAC) {modbus="FroniusBlk3:4"}
Number  Solar_PhVphA             "AC voltage phase AN [%.2f V]"           (gSolarAC) {modbus="FroniusBlk3:7"}
Number  Solar_PhVphB             "AC voltage phase BN [%.2f V]"           (gSolarAC) {modbus="FroniusBlk3:8"}
Number  Solar_PhVphC             "AC voltage phase CN [%.2f V]"           (gSolarAC) {modbus="FroniusBlk3:9"}

Number  Solar_AC_Power           "AC power [%.2f W]"                      (gSolarAC) {modbus="FroniusBlk4:0"}
Number  Solar_AC_Freq            "AC frequency [%.2f  Hz]"                 (gSolarAC) {modbus="FroniusBlk4:1"}
Number  Solar_WH                 "AC lifetime energy production [%.0f Wh]"(gSolarAC) {modbus="FroniusBlk4:5"}
//BCK 16/07/17 for some reason Solar_DCA & Solar_DCV below cause errors - need to look at it
//Number  Solar_DCA                "DC current [%.2f  A]"                    (gSolarDC) {modbus="FroniusBlk4:6"}
//Number  Solar_DCV                "DC voltage [%.2f  V]"                    (gSolarDC) {modbus="FroniusBlk4:7"}
Number  Solar_DCW                "DC power [%.2f  W]"                      (gSolarDC) {modbus="FroniusBlk4:8"}

Number  Solar_State              "Operating state (enum)[%d]"            (gSolarInfo) {modbus="FroniusBlk5:0"}

Number  Solar_EvtVnd1            "Event Flag 1 [%d]Bit field"          (gSolarInfo) {modbus="FroniusBlk6:0"}
Number  Solar_EvtVnd2            "Event Flag 2 [%d]Bit field"          (gSolarInfo) {modbus="FroniusBlk6:1"}
Number  Solar_EvtVnd3            "Event Flag 3 [%d]Bit field"          (gSolarInfo) {modbus="FroniusBlk6:2"}
Number  Solar_EvtVnd4            "Event Flag 4 [%d]Bit field"          (gSolarInfo) {modbus="FroniusBlk6:3"}

Number  Solar_1_DCA              "String 1 DC current [%d A]"           (gSolarDC) {modbus="FroniusBlk7:0"}
Number  Solar_1_DCV              "String 1 DC voltage [%d V]"           (gSolarDC) {modbus="FroniusBlk7:1"}
Number  Solar_1_DCW              "String 1 DC power [%d W]"             (gSolarDC) {modbus="FroniusBlk7:2"}
Number  Solar_1_Tmp              "String 1 Temperature [%d C]"          (gSolarDC) {modbus="FroniusBlk7:7"}
Number  Solar_1_DCSt             "String 1 Operating state [%d]"       (gSolarDC) {modbus="FroniusBlk7:8"}
Number  Solar_2_DCA              "String 2 DC current [%d A]"           (gSolarDC) {modbus="FroniusBlk7:20"}
Number  Solar_2_DCV              "String 2 DC voltage [%d V]"           (gSolarDC) {modbus="FroniusBlk7:21"}
Number  Solar_2_DCW              "String 2 DC power [%d W]"             (gSolarDC) {modbus="FroniusBlk7:22"}
Number  Solar_2_Tmp              "String 2 Temperature [%d C]"          (gSolarDC) {modbus="FroniusBlk7:27"}
Number  Solar_2_DCSt             "String 2 Operating state [%d]"       (gSolarDC) {modbus="FroniusBlk7:28"}

Hopefully somebody finds this useful.

Brent

1 Like

Hello Thomas,

I don’t use openhab but iobroker - but maybe you can help anyway :sunglasses:
You seem to be able to interpret the values that the inverter and the Modbus meter output.
Can you tell me how I can use the values to determine the current consumption of the house?
The value must be determined by the inverter as it is displayed in the SolarEdge web interface.

Here are the values I read from the Modbus counter:

 address   name   description   unit   type   len   factor   offset   role   room   poll   wp
40071   I_AC_Current   AC Total Current value   Amp   uint16be   1   1   0   level      true   false   
40075   I_AC_Current_SF   AC Current scale factor      int16be   1   1   0   level      true   false   
40083   I_AC_Power   AC Power value   W   int16be   1   1   0   level      true   false   
40084   I_AC_Power_SF   AC Power scale factor      int16be   1   1   0   level      true   false   
40085   I_AC_Frequency   AC Frequency value   Hz   uint16be   1   0.01   0   level      true   false   
40093   I_AC_Energy_WH   AC Lifetime Energy production   kWh   int32be   2   0.001   0   level      true   false   
40098   I_DC_Voltage   DC Voltage value   V   uint16be   1   0.1   0   level      true   false   
40100   I_DC_Power   DC Power Value   W   int16be   1   0.1   0   level      true   false   
40103   I_Temp_Sink   Temperatur   °C   int16be   1   1   0   level      true   false   
40107   I_Status   Operation State      uint16be   1   1   0   level      true   false   
40154   C_Option   Export + Import, Production, consumption,   NA   string   8   1   0   level      true   false   
40189   M_AC_Current   AC Current (sum of active phases)   A   int16be   1   1   0   level      true   false   
40193   M_AC_Current_S F   AC Current Scale Factor   SF   int16be   1   1   0   level      true   false   
40194   M_AC_Voltage_L N   Line to Neutral AC Voltage (average of active phases)   V   int16be   1   1   0   level      true   false   
40198   M_AC_Voltage_L L   Line to Line AC Voltage (average of active phases)   V   int16be   1   1   0   level      true   false   
40202   M_AC_Voltage_S F   AC Voltage Scale Factor   V   int16be   1   1   0   level      true   false   
40203   M_AC_Freq   AC Frequency   Hz   int16be   1   1   0   level      true   false   
40204   M_AC_Freq_SF   AC Frequency Scale Factor   SF   int16be   1   1   0   level      true   false   
40205   M_AC_Power   Total Real Power (sum of active phases)   W   uint16be   1   1   0   level      true   false   
40209   M_AC_Power_SF   AC Real Power Scale Factor   SW   int16be   1   1   0   level      true   false   
40210   M_AC_VA   Total AC Apparent Power (sum of active phases)   VA   int16be   1   1   0   level      true   false   
40214   M_AC_VA_SF   AC Apparent Power Scale Factor   SF   int16be   1   1   0   level      true   false   
40215   M_AC_VAR   Total AC Reactive Power (sum of active phases)   VAR   int16be   1   1   0   level      true   false   
40219   M_AC_VAR_SF   AC Reactive Power Scale Factor   %   int16be   1   1   0   level      true   false   
40220   M_AC_PF   Average Power Factor (average of active phases)   %   int16be   1   1   0   level      true   false   
40224   M_AC_PF_SF   AC Power Factor Scale Factor   SF   int16be   1   1   0   level      true   false   
40225   M_Exported   Total Exported Real Energy   Wh   uint32le   2   1   0   level      true   false   
40233   M_Imported   Total Imported Real Energy   Wh   uint32le   2   1   0   level      true   false   
40233   M_Imported   Total Imported Real Energy   Wh   uint32le   2   1   0   level      true   false   
40241   M_Energy_W_SF   Real Energy Scale Factor   Wh   int16be   1   1   0   level      true   false   
40242   M_Exported_VA   Total Exported Apparent Energy   VAh   uint32le   2   1   0   level      true   false   
40106   I_Temp_SF   Scale factor      int16be   1   1   0   level      true   false

Kind regards,
Olli

The current consumption of your house would be:

House = inverter power (I_AC_Power) + modbus meter power (M_AC_Power)

Assuming, that the modbus meter counts exported energy as negative values and imported as positive values.
As highlighted above, you need to use the scaling factor (M_AC_Power_SF) to scale your power values:

Modbus meter power = M_AC_Power * exp (10, M_AC_Power_SF)
Interver meter power = I_AC_Power * exp (10, I_AC_Power_SF)

BR,

Thomas

thx Thomas,

FYI, there is a new 2.x binding for Solaredge inverters which is using the web monitoring portal API for data, which is very easy to install and setup.
It’s the only solution for older inverters which lacks modbus communication port. You don’t even need a website API key.
Only the Solaredge web monitoring credentials are needed.

Keep in mind that the Solaredge API lags minutes behind the actual solar production. Therefore, if you want to steer the power consumption in your house to capitalise on the actual solar power being available (i.e. for matching the power you feed to your e-car, or dumping the excess energy into a heat storage solution, that is not controlled directly by your inverter), you need real-time data, which is what the direct access to the Modbus data provides.

Best,

Thomas

Has anyone found out, which modbus address represents the battery level? I’m using a SE 5000H with LG RESU10H. The sunspec documents is pretty silent about batteries and using several tools to monitor the modbus made me NOT find anything about the battery.