[OH3] MQTT 3 Interface to Victron CCGX

Hello,

This tutorial will show you how to display your solar power information from a Victron Energy Colour Control GX via the MQTT 3 binding on your openHAB 3 interface.

This tutorial assumes you already have ethernet or wifi connected and working on your CCGX, and a MQTT bridge and thing setup on your openHAB 3 setup.

Find the IP/host CCGX device. (I also add this IP to my /etc/hosts file to make life easier on the command line)

  • Install mosquitto clients for testing/debugging on your development machine (ie. on Debian);
sudo apt-get install mosquitto-clients

This gives us two clients. mosquitto_pub can be used to publish messages to a broker and mosquitto_sub can be used to subscribe to a topic to receive messages.

  • Find your CCGX VRM Portal ID in Settings->Services->VRM online portal or issue
mosquitto_sub -h ccgx -t "#"

Replace ccgx with your IP or add it to your system’s hosts file. The response will be a 12 character hex value and look something like

{"value": "a0f6fd5aa8c8"}

a0f6fd5aa8c8 is your portal ID, please substitute this ID in all further examples

  • Since the MQTT scripts on the CCGX go to sleep after 60 seconds let’s add a rule to let the CCGX know someone is listening and therefore keep sending information.
triggers:
  - id: "1"
    configuration:
      cronExpression: 0/30 * * * * ? *
    type: timer.GenericCronTrigger
conditions: []
actions:
  - inputs: {}
    id: "2"
    configuration:
      type: application/vnd.openhab.dsl.rule
      script: |
        val actions = getActions("mqtt", "mqtt:broker:ccgx")
        actions.publishMQTT("R/a0f6fd5aa8c8/system/0/Serial", "")
        logInfo("Solar", "CCGX MQTT Keep Alive Timer fired!!")
    type: script.ScriptAction

Now with the CCGX constantly sending out messages we can play around with what we want to read.

On the command line issue

mosquitto_sub -h ccgx -t "N/#" -v

to watch all the messages being sent from the CCGX. There is a lot! It will show the topic and the value. Assign the topics to individual channels through the GUI or code.

UID: mqtt:topic:ccgx:ccgx
label: CCGX
thingTypeUID: mqtt:topic
configuration: {}
bridgeUID: mqtt:broker:ccgx
location: Shed
channels:
  - id: pv_battery_soc
    channelTypeUID: mqtt:dimmer
    label: Battery SoC
    description: ""
    configuration:
      stateTopic: N/a0f6fd5aa8c8/system/0/Dc/Battery/Soc
      transformationPattern: JSONPATH:$.value
  - id: pv_battery_voltage
    channelTypeUID: mqtt:number
    label: Battery Voltage
    description: null
    configuration:
      formatBeforePublish: "%.4f"
      stateTopic: N/a0f6fd5aa8c8/system/0/Dc/Battery/Voltage
      transformationPattern: JSONPATH:$.value
  - id: pv_power_pv
    channelTypeUID: mqtt:number
    label: Solar Power
    description: null
    configuration:
      stateTopic: N/a0f6fd5aa8c8/system/0/Dc/Pv/Power
      transformationPattern: JSONPATH:$.value
  - id: pv_power_consumption
    channelTypeUID: mqtt:number
    label: Consumption
    description: null
    configuration:
      stateTopic: N/a0f6fd5aa8c8/system/0/Ac/Consumption/L1/Power
      transformationPattern: JSONPATH:$.value

Add new equipment to your semantic model. Add ‘points from thing’ to your equipment and choose your mqtt thing with all the channels added. They can now be viewed on the MainUI.

Enjoy!

2 Likes

Thanks @Zooka great work, I had some trouble getting my CCGX back online after switching to OH3. When I implement your “keep awake” rule in OH3 it does work, but it gives me the following error in the log - any ideas as to the cause? I have the correct ID.

[ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID '85056be4f0' failed: null

Thanks!

Was having issues too, try this one mate.

actions.get("mqtt", "mqtt:broker:1e24481776").publishMQTT("R/a0f6fd5aa8b8/system/0/Serial", "");

1 Like

@Zooka I owe you an apology, your initial rule actually works - I was pointing the getActions to the incorrect MQTT broker, your rule is working well now that the rule points to the correct broker. Rookie mistake…

2021-02-14 11:28:30.238 [INFO ] [org.openhab.core.model.script.Solar ] - CCGX MQTT Keep Alive Timer fired!!

Keep up that great work!

All good.

I figured out how to identify the charging state easier using Profiles. So no more having to use rules, etc… much cleaner.

MQTT topic
N/a0f6fd5aa8b8/solarcharger/258/State {"value": 3}

Add another channel to your Victron broker, add the item to model and apply a profile to it using MAP transformation.

$ cat /etc/openhab/transform/VictronChargerState.map

0=Off
2=Fault
3=Bulk
4=Absorption
5=Float
6=Storage
7=Equalize (manual)
11=Power supply mode
246=Repeated absorption
247=Auto equalize/Recondition
248=BatterySafe

Or you may prefer the overall system state.

N/a0f6fd5aa8b8/system/0/SystemState/State {"value": 9}

$ cat /etc/openhab/transform/VictronSystemState.map

0=Off
1=Low power
2=VE.Bus Fault condition
3=Bulk charging
4=Absorption charging
5=Float charging
6=Storage mode
7=Equalisation charging
8=Passthru
9=Inverting
10=Assisting
256=Discharging
257=Sustain

More.

Enjoy!

2 Likes

Hi @Zooka

thanks for your work! Was just migrated from a working OH2.5 system where everything was fine. However, on OH3 I’m struggling to get values other than “0” on the PV_Power channel (all other channels are working fine). I do see the PV_Power values in the console with “mosquitto_sub -h ccgx -t “#”” (during the day). Has anyone else seen this problem? Could it be that openhab looses connection after the PV_Power channel disappears during the night?

Thanks!

Update: one workarround is to restart the mqtt-broker. After that (if there is a value published on the the PV_Power channel) I get the actual values. However, after the next night (when PV_Power goes to sleep again) I only get the value “0” the next day even I do see other values in the mosquitto console…

Any hints on that problem?

Hello,
I also managed to display the data from the victron inverter in openhab but I receive this error now:

java.lang.IllegalArgumentException: json string can not be null or empty
        at com.jayway.jsonpath.internal.Utils.notEmpty(Utils.java:383)
        at com.jayway.jsonpath.internal.ParseContextImpl.parse(ParseContextImpl.java:36)
        at com.jayway.jsonpath.JsonPath.read(JsonPath.java:498)
        at org.openhab.transform.jsonpath.internal.JSonPathTransformationService.transform(JSonPathTransformationService.java:63)

I think we need an openhab rule that ignores all empty or null messages.
Does anyone help us?
Thank you

Hi,
Thanks for the examples, I have been able to set a keep alive rule and can view the ccgx messages via MQTT.fx so I know that works. However I cannot seem to get the values into OH3. I have tried so many different combinations but I never see any values. Any ideas or example setups that I can use please?

Things-Datei

Bridge mqtt:broker:venus [ host="192.168.xxx.xxx",port="1883", secure=false ]
Thing mqtt:topic:mything "mything" (mqtt:broker:venus) {
  Channels:
    Type number : V_AC_V_L1 "Victron Verbrauch L1" [ stateTopic="N/0035ff9a24d7/system/0/Ac/Consumption/L1/Power", transformationPattern="JSONPATH:$.value"]
    Type number : V_AC_V_L2 "Victron Verbrauch L2" [ stateTopic="N/0035ff9a24d7/system/0/Ac/Consumption/L2/Power", transformationPattern="JSONPATH:$.value"]
    Type number : V_AC_V_L3 "Victron Verbrauch L3" [ stateTopic="N/0035ff9a24d7/system/0/Ac/Consumption/L3/Power", transformationPattern="JSONPATH:$.value"]
    Type number : V_AC_G_L1 "Victron Netz L1"      [ stateTopic="N/0035ff9a24d7/system/0/Ac/Grid/L1/Power", transformationPattern="JSONPATH:$.value"]
    Type number : V_AC_G_L2 "Victron Netz L2"      [ stateTopic="N/0035ff9a24d7/system/0/Ac/Grid/L2/Power", transformationPattern="JSONPATH:$.value"]
    Type number : V_AC_G_L3 "Victron Netz L3"      [ stateTopic="N/0035ff9a24d7/system/0/Ac/Grid/L3/Power", transformationPattern="JSONPATH:$.value"]

    Type number : V_DC_Power "Victron DC Power"    [ stateTopic="N/0035ff9a24d7/battery/512/Dc/0/Power", transformationPattern="JSONPATH:$.value"]
    Type number : V_DC_Volt "Victron DC Volt"      [ stateTopic="N/0035ff9a24d7/battery/512/Dc/0/Voltage", transformationPattern="JSONPATH:$.value"]
    
    Type number : V_Batt_Soc "Victron Batt Soc"    [ stateTopic="N/0035ff9a24d7/system/0/Dc/Battery/Soc", transformationPattern="JSONPATH:$.value"]
    Type number : V_Batt_Temp "Victron Batt Temp"  [ stateTopic="N/0035ff9a24d7/system/0/Dc/Battery/Temperature", transformationPattern="JSONPATH:$.value"]
    Type number : V_Batt_Stat "Victron Batt State" [ stateTopic="N/0035ff9a24d7/system/0/Dc/Battery/State", transformationPattern="JSONPATH:$.value"]
    Type number : V_Batt_Stat1 "Victron Batt Status1"  [ stateTopic="N/0035ff9a24d7/system/0/Batteries", transformationPattern="JSONPATH:$.value[0].state"]
    
    Type number : V_Sys_Stat "Victron Sys Status"  [ stateTopic="N/0035ff9a24d7/system/0/SystemState/State", transformationPattern="JSONPATH:$.value"]
}

Items-Datei

Group Victron         "Victron"                          <energy>      (Garage)  ["Inverter"]
 Number V_AC_V_L1      "Victron Verbrauch L1 [%.1f W]"                 (Victron) ["Energy"]   { channel="mqtt:topic:mything:V_AC_V_L1" }
 Number V_AC_V_L2      "Victron Verbrauch L2 [%.1f W]"                 (Victron) ["Energy"]   { channel="mqtt:topic:mything:V_AC_V_L2" }
 Number V_AC_V_L3      "Victron Verbrauch L3 [%.1f W]"                 (Victron) ["Energy"]   { channel="mqtt:topic:mything:V_AC_V_L3" }
 Number V_AC_G_L1      "Victron Netz L1 [%.1f W]"                      (Victron) ["Energy"]   { channel="mqtt:topic:mything:V_AC_G_L1" }
 Number V_AC_G_L2      "Victron Netz L2 [%.1f W]"                      (Victron) ["Energy"]   { channel="mqtt:topic:mything:V_AC_G_L2" }
 Number V_AC_G_L3      "Victron Netz L3 [%.1f W]"                      (Victron) ["Energy"]   { channel="mqtt:topic:mything:V_AC_G_L3" }

 Number V_DC_Power     "Victron Battery Power [%.1f W]"                (Victron) ["Energy"]   { channel="mqtt:topic:mything:V_DC_Power" }
 Number V_DC_Volt      "Victron Battery Volt [%.1f V]"                 (Victron) ["Energy"]   { channel="mqtt:topic:mything:V_DC_Volt" }

 Number V_Batt_Soc     "Victron Battery Soc [%.1f %%]"  <battery>      (Victron) ["Energy"]   { channel="mqtt:topic:mything:V_Batt_Soc" }
 Number V_Batt_Temp    "Victron Battery Temp [%.1f °C]" <temperatur>   (Victron) ["Energy"]   { channel="mqtt:topic:mything:V_Batt_Temp" }
 Number V_Batt_Stat    "Victron Battery Status [MAP(VictronBatteryState.map):%s]" <text> (Victron) ["Energy"]   { channel="mqtt:topic:mything:V_Batt_Stat" }
 Number V_Batt_Stat1   "Victron Status [MAP(VictronSystemState.map):%s]" (Victron) ["Energy"] { channel="mqtt:topic:mything:V_Batt_Stat1" }

 Number V_Sys_Stat     "Victron Status [MAP(VictronSystemState.map):%s]" (Victron) ["Energy"] { channel="mqtt:topic:mything:V_Sys_Stat" }

Rule for Keep-Alive

val actions = getActions("mqtt", "mqtt:broker:venus")
actions.publishMQTT("R/xxxxxxxxxx/system/0/Serial", "")
logInfo("Solar", "CCGX MQTT Keep Alive Timer fired!!")