From 789b4d8e133e10337e87dbf96a72bcad5298b866 Mon Sep 17 00:00:00 2001 From: Martijn Versluis Date: Thu, 25 Jun 2026 14:55:44 +0200 Subject: [PATCH 1/2] Raise typed errors for the two known pair-endpoint failures --- lib/easee/client.rb | 7 +++++- lib/easee/errors.rb | 4 ++++ spec/easee/client_spec.rb | 50 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/lib/easee/client.rb b/lib/easee/client.rb index 86c03ef..7ce4c9e 100644 --- a/lib/easee/client.rb +++ b/lib/easee/client.rb @@ -176,10 +176,15 @@ def store_tokens(tokens) end def raise_credentials_or_request_error(error) - if error.response_status == 400 && [100, 727].include?(error.response.dig(:body, "errorCode")) + body_error_code = error.response&.dig(:body, "errorCode") + + if error.response_status == 400 && [100, 727].include?(body_error_code) raise Errors::InvalidCredentials, "Invalid username or password" end + raise Errors::InvalidPinCode.new("PIN code rejected", error.response) if body_error_code == 193 + raise Errors::ChargerNotFound.new("Charger not found", error.response) if body_error_code == 400 + raise request_failed(error) end diff --git a/lib/easee/errors.rb b/lib/easee/errors.rb index 1fed566..daa0d0f 100644 --- a/lib/easee/errors.rb +++ b/lib/easee/errors.rb @@ -17,6 +17,10 @@ def initialize(message, response = nil) class Forbidden < Base; end + class InvalidPinCode < RequestFailed; end + + class ChargerNotFound < RequestFailed; end + class RateLimitExceeded < RequestFailed def retryable? = true end diff --git a/spec/easee/client_spec.rb b/spec/easee/client_spec.rb index 413ae43..fc0f2cb 100644 --- a/spec/easee/client_spec.rb +++ b/spec/easee/client_spec.rb @@ -317,6 +317,56 @@ expect { client.pair(charger_id: "123ABC", pin_code: "1234") }.not_to raise_error end + + it "raises InvalidPinCode when Easee rejects the PIN (errorCode 193)" do + token_cache = ActiveSupport::Cache::MemoryStore.new + token_cache.write( + Easee::Client::TOKENS_CACHE_KEY, + { "accessToken" => "T123" }.to_json, + ) + + stub_request(:post, "https://api.easee.cloud/api/chargers/123ABC/pair?pinCode=WRONG") + .with(headers: { "Authorization" => "Bearer T123" }) + .to_return( + status: 400, + body: { + errorCode: 193, + errorCodeName: "NotPossibleToGrantAccessWithPinCode", + title: "Not possible to grant access with pin code", + }.to_json, + headers: { "Content-Type": "application/json" }, + ) + + client = Easee::Client.new(user_name: "easee", password: "money", token_cache:) + + expect { client.pair(charger_id: "123ABC", pin_code: "WRONG") } + .to raise_error(Easee::Errors::InvalidPinCode) + end + + it "raises ChargerNotFound when the charger is unknown (errorCode 400)" do + token_cache = ActiveSupport::Cache::MemoryStore.new + token_cache.write( + Easee::Client::TOKENS_CACHE_KEY, + { "accessToken" => "T123" }.to_json, + ) + + stub_request(:post, "https://api.easee.cloud/api/chargers/UNKNOWN/pair?pinCode=1234") + .with(headers: { "Authorization" => "Bearer T123" }) + .to_return( + status: 404, + body: { + errorCode: 400, + errorCodeName: "ChargerNotFound", + title: "Charger not found", + }.to_json, + headers: { "Content-Type": "application/json" }, + ) + + client = Easee::Client.new(user_name: "easee", password: "money", token_cache:) + + expect { client.pair(charger_id: "UNKNOWN", pin_code: "1234") } + .to raise_error(Easee::Errors::ChargerNotFound) + end end describe "#unpair" do From 7f9d68a7702465c92a32ef8c9db783ad397ce3fa Mon Sep 17 00:00:00 2001 From: Martijn Versluis Date: Thu, 25 Jun 2026 15:04:43 +0200 Subject: [PATCH 2/2] Match Easee errors purely on their errorCode --- lib/easee/client.rb | 12 ++++++------ lib/easee/errors.rb | 12 +++++++++--- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/lib/easee/client.rb b/lib/easee/client.rb index 7ce4c9e..ddaad9a 100644 --- a/lib/easee/client.rb +++ b/lib/easee/client.rb @@ -176,15 +176,15 @@ def store_tokens(tokens) end def raise_credentials_or_request_error(error) - body_error_code = error.response&.dig(:body, "errorCode") - - if error.response_status == 400 && [100, 727].include?(body_error_code) + case error.response&.dig(:body, "errorCode") + when *Errors::InvalidCredentials::CODES raise Errors::InvalidCredentials, "Invalid username or password" + when Errors::InvalidPinCode::CODE + raise Errors::InvalidPinCode.new("PIN code rejected", error.response) + when Errors::ChargerNotFound::CODE + raise Errors::ChargerNotFound.new("Charger not found", error.response) end - raise Errors::InvalidPinCode.new("PIN code rejected", error.response) if body_error_code == 193 - raise Errors::ChargerNotFound.new("Charger not found", error.response) if body_error_code == 400 - raise request_failed(error) end diff --git a/lib/easee/errors.rb b/lib/easee/errors.rb index daa0d0f..e1c6eaa 100644 --- a/lib/easee/errors.rb +++ b/lib/easee/errors.rb @@ -4,7 +4,9 @@ class Base < ::StandardError def retryable? = false end - class InvalidCredentials < Base; end + class InvalidCredentials < Base + CODES = [100, 727].freeze + end class RequestFailed < Base attr_reader :response @@ -17,9 +19,13 @@ def initialize(message, response = nil) class Forbidden < Base; end - class InvalidPinCode < RequestFailed; end + class InvalidPinCode < RequestFailed + CODE = 193 + end - class ChargerNotFound < RequestFailed; end + class ChargerNotFound < RequestFailed + CODE = 400 + end class RateLimitExceeded < RequestFailed def retryable? = true