Skip to content

Instantly share code, notes, and snippets.

@bicaluv
Last active February 12, 2023 15:56
Show Gist options
  • Save bicaluv/3f7cb3a052a22c3e64476f5820ce4074 to your computer and use it in GitHub Desktop.
Save bicaluv/3f7cb3a052a22c3e64476f5820ce4074 to your computer and use it in GitHub Desktop.
#!/usr/bin/env ruby
# Metadata allows your plugin to show up in the app, and website.
# changed from xbar to SwiftBar: https://github.com/swiftbar/SwiftBar
#
# <xbar.title>evcc</xbar.title>
# <xbar.version>v1.1</xbar.version>
# <xbar.author>naltatis</xbar.author>
# <xbar.author.github>naltatis</xbar.author.github>
# <xbar.desc>shows evcc solar charging stats</xbar.desc>
# <xbar.image>https://imgur.com/G1N1Ke0</xbar.image>
# <xbar.dependencies>ruby,evcc,solar,ev,homeautomation</xbar.dependencies>
# <xbar.abouturl>https://evcc.io/</xbar.abouturl>
# <swiftbar.hideAbout>false</swiftbar.hideAbout>
# <swiftbar.hideRunInTerminal>true</swiftbar.hideRunInTerminal>
# <swiftbar.hideLastUpdated>true</swiftbar.hideLastUpdated>
# <swiftbar.hideDisablePlugin>true</swiftbar.hideDisablePlugin>
# <swiftbar.hideSwiftBar>true</swiftbar.hideSwiftBar>
require 'net/http'
require 'json'
EVCC_SERVER = 'http://raspberrypi:7070'
# do self call to send http post api calls
if ARGV[0] == "writeApi"
uri = URI(ARGV[1])
res = Net::HTTP.post(uri, "")
exit
end
PHASES = {1 => "⓵", 2 => "⓶", 3 => "⓷"}
begin
response = JSON.parse(Net::HTTP.get(URI("#{EVCC_SERVER}/api/state")))
rescue
puts 'server not found| color=red'
return
end
result = response["result"]
gridPower = result["gridPower"]
# totalChargePower = (result["loadpoints"][0] { |sum, lp| sum + lp["chargePower"] }) / 1000.0
totalChargePower = 0
result['loadpoints'].each do |child|
if child["chargePower"] != nil
totalChargePower = totalChargePower + child['chargePower']
end
end
totalChargePower = totalChargePower / 1000.0
if totalChargePower > 0
puts "⚡️ %0.1f kW" % [totalChargePower]
elsif gridPower < 0
export = gridPower / -1000.0
puts "🏭◀ %0.1f kW" % [export]
else
import = gridPower / 1000.0
puts "🏭▶ %0.1f kW" % [import]
end
puts "---"
# Site
pvConfigured = result["pvConfigured"]
batteryConfigured = result["batteryConfigured"]
homePower = result["homePower"] / 1000.0
gridPower = result["gridPower"] / 1000.0
home = sprintf("🏠 %0.1f kW ", homePower)
grid = gridPower < 0 ? sprintf("🏭◀ %0.1f kW", gridPower * -1.0) : sprintf("🏭▶ %0.1f kW", gridPower)
pv = ""
if pvConfigured
pvPower = result["pvPower"] / 1000.0
pv = sprintf("☀️ %0.1f kW ", pvPower)
end
battery = ""
if batteryConfigured
batteryPower = result["batteryPower"] / 1000.0
batterySoC = result["batterySoC"]
battery = batteryPower < 0 ? sprintf("🔋◀ %0.1f kW", batteryPower * -1.0) : sprintf("🔋▶ %0.1f kW", batteryPower)
battery += sprintf(" (%d%%) ", batterySoC)
end
if batteryConfigured
puts "#{home}#{grid}"
puts "#{pv}#{battery}"
else
puts "#{home}#{pv}#{grid}"
end
puts "---"
# Loadpoints
activeLoadpoints = result["loadpoints"] # .select {|lp| lp["connected"] }
def buildMode(mode, modeText, lpId, curMode)
# https://docs.evcc.io/docs/reference/api/
# POST /api/loadpoints/<id>/mode/<mode> : off/pv/minpv/now
url = "#{EVCC_SERVER}/api/loadpoints/#{lpId}/mode/#{mode}"
selfCall = "| shell=\"#{File.expand_path(__FILE__)}\" param1=writeApi param2=#{url} terminal=false refresh=true checked=#{curMode == mode}"
"--" << modeText << selfCall
end
lpId = 1
# *** ACHTUNG *** ggf prüfen, wenn mehr als ein loadpoint, ob man über alle gehen muss, nicht nur die aktiven
activeLoadpoints.each do |lp|
chargePower = 0
if lp["chargePower"] != nil
chargePower = lp["chargePower"] / 1000.0
end
vehicleSoC = lp["vehicleSoC"]
vehicleRange = lp["vehicleRange"]
chargedEnergy = lp["chargedEnergy"] / 1000.0
vehicleTitle = lp["vehicleTitle"]
puts "🚘 #{vehicleTitle}| refresh=true"
puts buildMode("off", "Aus", lpId, lp["mode"])
puts buildMode("minpv", "Min+PV", lpId, lp["mode"])
puts buildMode("pv", "PV", lpId, lp["mode"])
puts buildMode("now", "Schnell", lpId, lp["mode"])
if lp["hasVehicle"]
puts " ↳ 🔋 %d%% (%d km) | trim=false" % [vehicleSoC, vehicleRange]
end
puts " ↳ ⚡️ %0.1f kW #{PHASES[lp["activePhases"]]} (+%0.1f kWh) | trim=false" % [chargePower, chargedEnergy]
puts "---"
lpId = lpId + 1
end
if activeLoadpoints.length == 0
puts "no vehicle connected"
puts "---"
end
# Savings
savingsTotalCharged = result["savingsTotalCharged"] || 0
savingsSelfConsumptionCharged = result["savingsSelfConsumptionCharged"] || 0
savingsAmount = result["savingsAmount"] || 0
energyPrice = result["savingsEffectivePrice"] || result["tariffGrid"]
selfPercent = result["savingsSelfConsumptionPercent"] || 0
puts "☀️ %d%% (∑ %0.1f of %0.1f kWh)" % [selfPercent, savingsSelfConsumptionCharged, savingsTotalCharged]
puts "💰 %0.2f€ (%0.2f ct/kWh)" % [savingsAmount, energyPrice]
puts "---"
puts "open evcc| href=#{EVCC_SERVER}"
puts "open raspberry pi UI| href=https://raspberrypi:10000"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment