{"id":4729,"date":"2025-02-28T21:28:40","date_gmt":"2025-03-01T04:28:40","guid":{"rendered":"http:\/\/www.sheer.us\/weblogs\/?p=4729"},"modified":"2025-02-28T21:28:40","modified_gmt":"2025-03-01T04:28:40","slug":"victron-energy-munin-plugins-for-cerbo-gx-monitoring","status":"publish","type":"post","link":"http:\/\/www.sheer.us\/weblogs\/programming\/perl\/victron-energy-munin-plugins-for-cerbo-gx-monitoring","title":{"rendered":"Victron Energy munin plugins for Cerbo GX monitoring"},"content":{"rendered":"<p>Charger amps<\/p>\n<p><PRE><br \/>\n#!\/usr\/bin\/perl<\/p>\n<p>use Device::Modbus::TCP::Client;<\/p>\n<p>my $client = Device::Modbus::TCP::Client->new(<br \/>\n         host => &#8216;put your GX ip or name here&#8217;<br \/>\n);<\/p>\n<p>$config = 1 if(&#8220;config&#8221; ~~ @ARGV);<br \/>\n$chargers = [ 223, 224, 226, 238, 239 ]; # devices<\/p>\n<p>if($config) {<br \/>\n        print &#8220;graph_title charger amps\\n&#8221;;<br \/>\n        print &#8220;graph_category victron\\n&#8221;;<br \/>\n        foreach $charger (@{$chargers}) {<br \/>\n                print $charger . &#8220;_amps.label Amps\\n&#8221;;<br \/>\n        }<br \/>\n} else {<br \/>\n        foreach $charger (@{$chargers}) {<br \/>\n                my $req = $client->read_holding_registers( unit => $charger, address => 772, quantity => 1 );<br \/>\n                $client->send_request($req) || die &#8220;Send error: $!&#8221;;<br \/>\n                my $response = $client->receive_response;<br \/>\n                print $charger . &#8220;_amps.value &#8221; . uint16_to_int( @{$response->{&#8216;message&#8217;}->{&#8216;values&#8217;}}[0]) \/ 10 . &#8220;\\n&#8221;;<\/p>\n<p>        }<br \/>\n}<\/p>\n<p>sub uint16_to_int {<br \/>\n    my $uint16 = shift;<br \/>\n    return $uint16 > 0x7FFF ? $uint16 &#8211; 0x10000 : $uint16;<br \/>\n}<br \/>\n<\/PRE><\/p>\n<p>Charger overall power<\/p>\n<p><PRE><br \/>\n#!\/usr\/bin\/perl<\/p>\n<p>use Device::Modbus::TCP::Client;<\/p>\n<p>my $client = Device::Modbus::TCP::Client->new(<br \/>\n         host => &#8216;put your GX ip or name here&#8217;<br \/>\n);<\/p>\n<p>$config = 1 if(&#8220;config&#8221; ~~ @ARGV);<\/p>\n<p>$chargers = [ 223, 224, 226, 238, 239 ]; # adjust with your actual list. See Settings -> Services -> Modbus for a list<\/p>\n<p>if($config) {<br \/>\n        print &#8220;graph_title charger total watts\\n&#8221;;<br \/>\n        print &#8220;graph_category victron\\n&#8221;;<br \/>\n        print &#8220;total_watts.label watts\\n&#8221;;<br \/>\n} else {<br \/>\n        my $total = 0;<\/p>\n<p>        foreach $charger (@{$chargers}) {<br \/>\n                my $req = $client->read_holding_registers( unit => $charger, address => 789, quantity => 1 );<br \/>\n                $client->send_request($req) || die &#8220;Send error: $!&#8221;;<br \/>\n                my $response = $client->receive_response;<br \/>\n                $total += uint16_to_int( @{$response->{&#8216;message&#8217;}->{&#8216;values&#8217;}}[0]) \/ 10;<br \/>\n        }<\/p>\n<p>        print &#8220;total_watts.value $total\\n&#8221;;<br \/>\n}<\/p>\n<p>sub uint16_to_int {<br \/>\n    my $uint16 = shift;<br \/>\n    return $uint16 > 0x7FFF ? $uint16 &#8211; 0x10000 : $uint16;<br \/>\n}<br \/>\n<\/PRE><\/p>\n<p>Charger individual power<\/p>\n<p><PRE><br \/>\n#!\/usr\/bin\/perl<\/p>\n<p>use Device::Modbus::TCP::Client;<\/p>\n<p>my $client = Device::Modbus::TCP::Client->new(<br \/>\n         host => &#8216;put your GX name or IP here&#8217;<br \/>\n);<\/p>\n<p>$config = 1 if(&#8220;config&#8221; ~~ @ARGV);<\/p>\n<p>$chargers = [ 223, 224, 226, 238, 239 ];<\/p>\n<p>if($config) {<br \/>\n        print &#8220;graph_title charger watts\\n&#8221;;<br \/>\n        print &#8220;graph_category victron\\n&#8221;;<br \/>\n        foreach $charger (@{$chargers}) {<br \/>\n                print $charger . &#8220;_watts.label Amps\\n&#8221;;<br \/>\n        }<br \/>\n} else {<br \/>\n        foreach $charger (@{$chargers}) {<br \/>\n                my $req = $client->read_holding_registers( unit => $charger, address => 789, quantity => 1 );<br \/>\n                $client->send_request($req) || die &#8220;Send error: $!&#8221;;<br \/>\n                my $response = $client->receive_response;<br \/>\n                print $charger . &#8220;_watts.value &#8221; . uint16_to_int( @{$response->{&#8216;message&#8217;}->{&#8216;values&#8217;}}[0]) \/ 10 . &#8220;\\n&#8221;;<\/p>\n<p>        }<br \/>\n}<\/p>\n<p>sub uint16_to_int {<br \/>\n    my $uint16 = shift;<br \/>\n    return $uint16 > 0x7FFF ? $uint16 &#8211; 0x10000 : $uint16;<br \/>\n}<br \/>\n<\/PRE><\/p>\n<p>inverter state of charge<\/p>\n<p><PRE><br \/>\n#!\/usr\/bin\/perl<\/p>\n<p>use Device::Modbus::TCP::Client;<\/p>\n<p>my $client = Device::Modbus::TCP::Client->new(<br \/>\n         host => &#8216;put your GX name or IP here&#8217;<br \/>\n);<\/p>\n<p>$config = 1 if(&#8220;config&#8221; ~~ @ARGV);<\/p>\n<p>my $req = $client->read_holding_registers( unit => 227, address => 30, quantity => 1 );<\/p>\n<p>$client->send_request($req) || die &#8220;Send error: $!&#8221;;<br \/>\nmy $response = $client->receive_response;<\/p>\n<p>if($config) {<br \/>\n        print &#8220;graph_title state of charge\\n&#8221;;<br \/>\n        print &#8220;graph_category victron\\n&#8221;;<br \/>\n        print &#8220;inv_soc.label SOC\\n&#8221;;<br \/>\n} else {<br \/>\n        print &#8220;inv_soc.value &#8221; . uint16_to_int( @{$response->{&#8216;message&#8217;}->{&#8216;values&#8217;}}[0]) \/ 10 . &#8220;\\n&#8221;;<br \/>\n}<\/p>\n<p>sub uint16_to_int {<br \/>\n    my $uint16 = shift;<br \/>\n    return $uint16 > 0x7FFF ? $uint16 &#8211; 0x10000 : $uint16;<br \/>\n}<br \/>\n<\/PRE><\/p>\n<p>Inverter bus voltage<\/p>\n<p><PRE><br \/>\n#!\/usr\/bin\/perl<br \/>\nuse Device::Modbus::TCP::Client;<\/p>\n<p>my $client = Device::Modbus::TCP::Client->new(<br \/>\n         host => &#8216;your GX device goes here&#8217;<br \/>\n);<\/p>\n<p>$config = 1 if(&#8220;config&#8221; ~~ @ARGV);<\/p>\n<p>my $req = $client->read_holding_registers( unit => 227, address => 26, quantity => 2 );<\/p>\n<p>$client->send_request($req) || die &#8220;Send error: $!&#8221;;<br \/>\nmy $response = $client->receive_response;<\/p>\n<p>if($config) {<br \/>\n        print &#8220;graph_title battery volts\\n&#8221;;<br \/>\n        print &#8220;graph_category victron\\n&#8221;;<br \/>\n        print &#8220;inv_volts.label Volts\\n&#8221;;<br \/>\n} else {<br \/>\n        print &#8220;inv_volts.value &#8221; . @{$response->{&#8216;message&#8217;}->{&#8216;values&#8217;}}[0] \/100 . &#8220;\\n&#8221;;<br \/>\n}<br \/>\n<\/PRE><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Charger amps #!\/usr\/bin\/perl use Device::Modbus::TCP::Client; my $client = Device::Modbus::TCP::Client->new( host => &#8216;put your GX ip or name here&#8217; ); $config = 1 if(&#8220;config&#8221; ~~ @ARGV); $chargers = [ 223, 224, 226, 238, 239 ]; # devices if($config) { print &#8220;graph_title charger amps\\n&#8221;; print &#8220;graph_category victron\\n&#8221;; foreach $charger (@{$chargers}) { print $charger . &#8220;_amps.label Amps\\n&#8221;; } [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4,3],"tags":[],"_links":{"self":[{"href":"http:\/\/www.sheer.us\/weblogs\/wp-json\/wp\/v2\/posts\/4729"}],"collection":[{"href":"http:\/\/www.sheer.us\/weblogs\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.sheer.us\/weblogs\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.sheer.us\/weblogs\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/www.sheer.us\/weblogs\/wp-json\/wp\/v2\/comments?post=4729"}],"version-history":[{"count":1,"href":"http:\/\/www.sheer.us\/weblogs\/wp-json\/wp\/v2\/posts\/4729\/revisions"}],"predecessor-version":[{"id":4730,"href":"http:\/\/www.sheer.us\/weblogs\/wp-json\/wp\/v2\/posts\/4729\/revisions\/4730"}],"wp:attachment":[{"href":"http:\/\/www.sheer.us\/weblogs\/wp-json\/wp\/v2\/media?parent=4729"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.sheer.us\/weblogs\/wp-json\/wp\/v2\/categories?post=4729"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.sheer.us\/weblogs\/wp-json\/wp\/v2\/tags?post=4729"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}