Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions lib/easee/archived_session.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
module Easee
class ArchivedSession
def initialize(data)
@data = data.deep_symbolize_keys
end

def id = @data.fetch(:id)
def charger_id = @data.fetch(:chargerId)

def car_connected = parse_time(:carConnected)
def car_disconnected = parse_time(:carDisconnected)
def first_energy_transfer_period_started = parse_time(:firstEnergyTransferPeriodStarted)
def last_energy_transfer_period_end = parse_time(:lastEnergyTransferPeriodEnd)

def energy_kwh = @data.fetch(:kiloWattHours).to_f
def duration_seconds = @data[:actualDurationSeconds]

def complete? = @data.fetch(:isComplete, false)

def auth_token = @data[:authToken]
def auth_user = @data[:authUser]

private

def parse_time(key)
value = @data[key]
return if value.nil?

Time.zone.parse(value)
end
end
end
10 changes: 10 additions & 0 deletions lib/easee/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@ def ongoing_session(charger_id)
.then { |response| Session.new(response.body) }
end

# https://developer.easee.com/reference/chargingsessionscharger_getchargersessionsbycharger
def sessions(charger_id, from:, to:)
path = "/api/sessions/charger/#{charger_id}/sessions/#{format_time(from)}/#{format_time(to)}"
get(path).then { |response| response.body.map { |session| ArchivedSession.new(session) } }
end

# https://developer.easee.cloud/reference/get_api-chargers-id-config
def configuration(charger_id)
get("/api/chargers/#{charger_id}/config")
Expand Down Expand Up @@ -114,6 +120,10 @@ def authenticated_connection
end
end

def format_time(time)
time.getutc.iso8601
end

def get(endpoint, query = {})
with_error_handling do
authenticated_connection.get("#{BASE_URL}#{endpoint}", query)
Expand Down
1 change: 1 addition & 0 deletions lib/stekker_easee.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
require_relative "easee/configuration"
require_relative "easee/errors"
require_relative "easee/meter_reading"
require_relative "easee/archived_session"
require_relative "easee/session"
require_relative "easee/site"
require_relative "easee/state"
Expand Down
48 changes: 48 additions & 0 deletions spec/easee/archived_session_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
RSpec.describe Easee::ArchivedSession do
it "exposes the session fields" do
session = described_class.new(
"id" => 387,
"chargerId" => "EH98AAGY",
"carConnected" => "2026-01-02T19:23:23Z",
"carDisconnected" => "2026-01-03T11:57:00Z",
"firstEnergyTransferPeriodStarted" => "2026-01-02T20:00:05+00:00",
"lastEnergyTransferPeriodEnd" => "2026-01-03T11:57:00+00:00",
"kiloWattHours" => 29.155331,
"actualDurationSeconds" => 10558,
"isComplete" => true,
"authToken" => "FD2ACA9C",
"authUser" => 709817,
)

expect(session).to have_attributes(
id: 387,
charger_id: "EH98AAGY",
car_connected: Time.zone.parse("2026-01-02T19:23:23Z"),
car_disconnected: Time.zone.parse("2026-01-03T11:57:00Z"),
first_energy_transfer_period_started: Time.zone.parse("2026-01-02T20:00:05Z"),
last_energy_transfer_period_end: Time.zone.parse("2026-01-03T11:57:00Z"),
energy_kwh: 29.155331,
duration_seconds: 10558,
complete?: true,
auth_token: "FD2ACA9C",
auth_user: 709817,
)
end

it "treats missing car_connected and car_disconnected as nil" do
session = described_class.new(
"id" => 388,
"chargerId" => "EH98AAGY",
"kiloWattHours" => 0.0,
"isComplete" => false,
)

expect(session).to have_attributes(
car_connected: nil,
car_disconnected: nil,
first_energy_transfer_period_started: nil,
last_energy_transfer_period_end: nil,
complete?: false,
)
end
end
77 changes: 77 additions & 0 deletions spec/easee/client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -828,6 +828,83 @@
end
end

describe "#sessions" do
it "fetches the completed sessions for a charger in the given time range" do
token_cache = ActiveSupport::Cache::MemoryStore.new
token_cache.write(
Easee::Client::TOKENS_CACHE_KEY,
{ "accessToken" => "T123" }.to_json,
)

from = Time.zone.parse("2026-01-01T00:00:00Z")
to = Time.zone.parse("2026-07-17T00:00:00Z")

stub_request(
:get,
"https://api.easee.cloud/api/sessions/charger/EH98AAGY/sessions/2026-01-01T00:00:00Z/2026-07-17T00:00:00Z",
)
.with(headers: { "Authorization" => "Bearer T123" })
.to_return(
status: 200,
body: [
{
id: 387,
chargerId: "EH98AAGY",
carConnected: "2026-01-02T19:23:23Z",
carDisconnected: "2026-01-03T11:57:00Z",
kiloWattHours: 29.155331,
isComplete: true,
},
{
id: 388,
chargerId: "EH98AAGY",
carConnected: "2026-01-08T17:15:48Z",
carDisconnected: nil,
kiloWattHours: 0.0,
isComplete: false,
},
].to_json,
headers: { "Content-Type": "application/json" },
)

client = Easee::Client.new(user_name: "easee", password: "money", token_cache:)

sessions = client.sessions("EH98AAGY", from:, to:)

expect(sessions.map(&:id)).to eq [387, 388]
expect(sessions.first).to have_attributes(
charger_id: "EH98AAGY",
car_connected: Time.zone.parse("2026-01-02T19:23:23Z"),
car_disconnected: Time.zone.parse("2026-01-03T11:57:00Z"),
energy_kwh: 29.155331,
complete?: true,
)
expect(sessions.last).to have_attributes(car_disconnected: nil, complete?: false)
end

it "converts non-UTC timestamps to UTC before sending them to Easee" do
token_cache = ActiveSupport::Cache::MemoryStore.new
token_cache.write(
Easee::Client::TOKENS_CACHE_KEY,
{ "accessToken" => "T123" }.to_json,
)

from = Time.new(2026, 1, 1, 1, 0, 0, "+01:00")
to = Time.new(2026, 1, 2, 3, 0, 0, "+02:00")

request = stub_request(
:get,
"https://api.easee.cloud/api/sessions/charger/EH98AAGY/sessions/2026-01-01T00:00:00Z/2026-01-02T01:00:00Z",
).to_return(status: 200, body: "[]", headers: { "Content-Type": "application/json" })

client = Easee::Client.new(user_name: "easee", password: "money", token_cache:)

client.sessions("EH98AAGY", from:, to:)

expect(request).to have_been_requested
end
end

describe "#inspect" do
it "does not include the user name and password" do
token_cache = ActiveSupport::Cache::MemoryStore.new
Expand Down