From 36cb82db87d184ccdffa36a39f4df9a85dc14277 Mon Sep 17 00:00:00 2001 From: Alec O'Connor Date: Tue, 4 May 2021 09:39:07 -0400 Subject: [PATCH 1/3] Skip Malformed Rows (those missing an end_date) *Expected* The Charges endpoint should still return data, even if a portion of charges have corrupted data. *How it happens* Charges can become corrupted if Teslamate does not detect that a charge ever ended, such as if the car or Teslamate goes offline when the charging ends. *Note* The charging_processes table's most recent row may be missing an end_date if the charge is in progress. These charges were already being skipped in the chargingDetails endpoint. I am assuming it is safe to skip them here, since they essentially have no data until the charge finishes. *Please Test* - Please test that this still builds as I am not entirely familiar with Go and am unsure how to test this on my docker container. --- src/v1_TeslaMateAPICarsCharges.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/v1_TeslaMateAPICarsCharges.go b/src/v1_TeslaMateAPICarsCharges.go index bbc34f2..996bac0 100644 --- a/src/v1_TeslaMateAPICarsCharges.go +++ b/src/v1_TeslaMateAPICarsCharges.go @@ -121,6 +121,11 @@ func TeslaMateAPICarsChargesV1(c *gin.Context) { // looping through all results for rows.Next() { + + // skip any malformed rows + if end_date == NULL { + continue + } // creating charge object based on struct charge := Charges{} From 27646b20583a7cdce091fdc95fd4e5da0f337b6b Mon Sep 17 00:00:00 2001 From: Alec O'Connor Date: Mon, 10 May 2021 09:54:30 -0400 Subject: [PATCH 2/3] Prevent fatal error when detailed charge malformed Following up on https://github.com/tobiasehlert/teslamateapi/issues/43 *Reason* A detailed charge is malformed if the end_date is missing in SQL. It's also possible a charge that is in progress will be missing this value as well, in which case this detailed charge isn't populated with data. *Better Solutions* (long term) Adjust error handling across the API: - *Opt 1:* Instead of `ValidResponse` being a boolean, replace with `ResponseError`. Change the if statement at the bottom of each file to check for the `ResponseError`'s existence instead of `if ValidResponse {...} else {...}`. Remove all log.Fatal(err) so that the API can still return responses gracefully, and set status to 200 OK since the response will still technically be HTTP valid. Break execution of further steps and return the meaningful ResponseError in the API - *Opt 2:* For simplicity, create a functions like this and call it (along with an early `return`) wherever a fatal error is currently used (or `ValidResponse` never set to true). Then remove `ValidResponse` entirely and adjust the `if` statement at the bottom of every API file to only run the first condition. ``` func TeslaMateAPIHandleErrorResponse(c *gin.Context, s string) { log.Println("[error] TeslaMateAPICarsChargesDetailsV1 " + c.Request.RequestURI + " error in execution! " + s) c.JSON(http.StatusOK, gin.H{"error": s}) } func TeslaMateAPIHandleSuccessResponse(c *gin.Context, j JSONData) { log.Println("[info] TeslaMateAPICarsChargesDetailsV1 " + c.Request.RequestURI + " executed successful.") c.JSON(http.StatusOK, j) } ``` If you're interested, I'd be happy to put together a sample PR --- src/v1_TeslaMateAPICarsChargesDetails.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/v1_TeslaMateAPICarsChargesDetails.go b/src/v1_TeslaMateAPICarsChargesDetails.go index b6e39d0..5b9100b 100644 --- a/src/v1_TeslaMateAPICarsChargesDetails.go +++ b/src/v1_TeslaMateAPICarsChargesDetails.go @@ -150,6 +150,11 @@ func TeslaMateAPICarsChargesDetailsV1(c *gin.Context) { // looping through all results for rows.Next() { + + // skip a malformed charge + if end_date == NULL { + break + } // creating charge object based on struct charge := Charge{} From ef40a91e8d98f4cb6ca5188d50eee30daec43751 Mon Sep 17 00:00:00 2001 From: Tobias Lindberg Date: Wed, 19 May 2021 19:10:05 +0200 Subject: [PATCH 3/3] adding sql when end_date is not null to charges --- src/v1_TeslaMateAPICarsCharges.go | 7 +------ src/v1_TeslaMateAPICarsChargesDetails.go | 7 +------ 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/src/v1_TeslaMateAPICarsCharges.go b/src/v1_TeslaMateAPICarsCharges.go index 996bac0..67c4b68 100644 --- a/src/v1_TeslaMateAPICarsCharges.go +++ b/src/v1_TeslaMateAPICarsCharges.go @@ -106,7 +106,7 @@ func TeslaMateAPICarsChargesV1(c *gin.Context) { LEFT JOIN addresses address ON address_id = address.id LEFT JOIN positions position ON position_id = position.id LEFT JOIN geofences geofence ON geofence_id = geofence.id - WHERE charging_processes.car_id=$1 + WHERE charging_processes.car_id=$1 AND charging_processes.end_date IS NOT NULL ORDER BY start_date DESC LIMIT $2 OFFSET $3;` rows, err := db.Query(query, CarID, ResultShow, ResultPage) @@ -121,11 +121,6 @@ func TeslaMateAPICarsChargesV1(c *gin.Context) { // looping through all results for rows.Next() { - - // skip any malformed rows - if end_date == NULL { - continue - } // creating charge object based on struct charge := Charges{} diff --git a/src/v1_TeslaMateAPICarsChargesDetails.go b/src/v1_TeslaMateAPICarsChargesDetails.go index 5b9100b..1c05ecf 100644 --- a/src/v1_TeslaMateAPICarsChargesDetails.go +++ b/src/v1_TeslaMateAPICarsChargesDetails.go @@ -136,7 +136,7 @@ func TeslaMateAPICarsChargesDetailsV1(c *gin.Context) { LEFT JOIN positions position ON position_id = position.id LEFT JOIN geofences geofence ON geofence_id = geofence.id LEFT JOIN charges ON charging_processes.id = charges.id - WHERE charging_processes.car_id=$1 AND charging_processes.id=$2 + WHERE charging_processes.car_id=$1 AND charging_processes.id=$2 AND charging_processes.end_date IS NOT NULL ORDER BY start_date DESC;` rows, err := db.Query(query, CarID, ChargeID) @@ -150,11 +150,6 @@ func TeslaMateAPICarsChargesDetailsV1(c *gin.Context) { // looping through all results for rows.Next() { - - // skip a malformed charge - if end_date == NULL { - break - } // creating charge object based on struct charge := Charge{}