#!/usr/bin/env ruby # frozen_string_literal: true # See documentation at the end of this file. require 'json' require 'net/http' require 'uri' if ARGV.length != 1 || ARGV.first != 'config' raise 'Error: plugin designed for the dirtyconfig protocol, must be run with the config argument' end basename = File.basename($0) address = basename.split('tesla_wall_connector_').last raise 'Error: address not set' if address.nil? fieldname = basename.gsub(/[^A-Za-z0-9_]/, '_') uri_prefix = "http://#{address}/api/1/" responses = {} %w[ vitals wifi_status lifetime ].each do |endpoint| responses[endpoint] = JSON.parse( Net::HTTP.get_response(URI("#{uri_prefix}#{endpoint}")).body ) end puts <<~MUNIN multigraph #{fieldname}_times graph_title Tesla Wall Connector #{address} Times graph_args --base 1000 --lower-limit 0 graph_scale no graph_vlabel Time (days) graph_category tesla poweron.label Power On Time poweron.draw AREA poweron.type GAUGE poweron.value #{responses['lifetime']['uptime_s'] / 86_400.0} uptime.label Uptime uptime.draw AREA uptime.type GAUGE uptime.value #{responses['vitals']['uptime_s'] / 86_400.0} charging.label Charging Time charging.type GAUGE charging.draw LINE2 charging.value #{responses['lifetime']['charging_time_s'] / 86_400.0} session.label Session session.type GAUGE session.draw LINE2 session.value #{responses['vitals']['session_s'] / 86_400.0} multigraph #{fieldname}_power graph_title Tesla Wall Connector #{address} Power Output graph_args --base 1000 --lower-limit 0 graph_vlabel Power (W) graph_category tesla power.label Power output power.type DERIVE power.min 0 power.value #{(responses['vitals']['session_energy_wh'] * 3600.0).round} multigraph #{fieldname}_cycles graph_title Tesla Wall Connector #{address} Cycle Counts graph_args --base 1000 --lower-limit 0 graph_scale no graph_category tesla contactor.label Contactor contactor.draw AREA contactor.type GAUGE contactor.value #{responses['lifetime']['contactor_cycles']} connector.label Connector connector.draw AREA connector.type GAUGE connector.value #{responses['lifetime']['connector_cycles']} contactor_loaded.label Contactor (loaded) contactor_loaded.draw AREA contactor_loaded.type GAUGE contactor_loaded.value #{responses['lifetime']['contactor_cycles_loaded']} alerts.label Alerts alerts.type GAUGE alerts.draw LINE2 alerts.value #{responses['lifetime']['alert_count']} thermal_foldbacks.label Thermal foldbacks thermal_foldbacks.type GAUGE thermal_foldbacks.draw LINE2 thermal_foldbacks.value #{responses['lifetime']['thermal_foldbacks']} multigraph #{fieldname}_voltage graph_title Tesla Wall Connector #{address} Voltages graph_category tesla graph_vlabel Voltage (V) grid.label Grid grid.type GAUGE grid.value #{responses['vitals']['grid_v']} A.label A A.type GAUGE A.value #{responses['vitals']['voltageA_v']} B.label B B.type GAUGE B.value #{responses['vitals']['voltageB_v']} C.label C C.type GAUGE C.value #{responses['vitals']['voltageC_v']} relay_coil.label Relay coil relay_coil.type GAUGE relay_coil.value #{responses['vitals']['relay_coil_v']} multigraph #{fieldname}_frequency graph_title Tesla Wall Connector #{address} Frequency graph_category tesla graph_args --base 1000 --lower-limit 0 graph_vlabel Frequency (Hz) grid.label Grid grid.type GAUGE grid.value #{responses['vitals']['grid_hz']} multigraph #{fieldname}_current graph_title Tesla Wall Connector #{address} Currents graph_category tesla graph_args --base 1000 --lower-limit 0 graph_vlabel Current (A) vehicle.label Vehicle vehicle.type GAUGE vehicle.value #{responses['vitals']['vehicle_current_a']} A.label A A.type GAUGE A.value #{responses['vitals']['currentA_a']} B.label B B.type GAUGE B.value #{responses['vitals']['currentB_a']} C.label C C.type GAUGE C.value #{responses['vitals']['currentC_a']} N.label N N.type GAUGE N.value #{responses['vitals']['currentN_a']} multigraph #{fieldname}_temperature graph_title Tesla Wall Connector #{address} Temperatures graph_category tesla graph_vlabel Temperature (°C) pcba.label PCBA pcba.type GAUGE pcba.value #{responses['vitals']['pcba_temp_c']} handle.label Handle handle.type GAUGE handle.value #{responses['vitals']['handle_temp_c']} mcu.label MCU mcu.type GAUGE mcu.value #{responses['vitals']['mcu_temp_c']} multigraph #{fieldname}_wifi graph_title Tesla Wall Connector #{address} Wi-Fi graph_category tesla signal_strength.label Signal strength signal_strength.type GAUGE signal_strength.value #{responses['wifi_status']['wifi_signal_strength']} rssi.label RSSI rssi.type GAUGE rssi.value #{responses['wifi_status']['wifi_rssi']} snr.label SNR snr.type GAUGE snr.value #{responses['wifi_status']['wifi_snr']} MUNIN __END__ =pod =encoding utf8 =head1 NAME tesla_wall_connector_ - Munin wildcard plugin for graphing data from Tesla Wall Connector electric vehicle charging stations. =head1 CONFIGURATION =head2 WILDCARD PLUGIN This is a wildcard plugin. The wildcard suffix in the symlink is the hostname or IP address of the Wall Connector that you want to monitor. Examples: =over =item tesla_wall_connector_wallconnector.example.com =item tesla_wall_connector_203.0.113.1 =item tesla_wall_connector_2001:db8::1 =back =head1 NOTES Requires the multigraph and dirtyconfig capabilities available in munin 2.0 and newer. Developed and tested with Tesla Wall Connector generation 3 firmware version 24.36.3+g3f585e7b51cc72, part numbers 1457768-02-G and 1457768-02-H (from C). =head1 AUTHOR Copyright © Kenyon Ralph =head1 LICENSE This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see L. =cut