mirror of
https://github.com/tobiasehlert/teslamateapi.git
synced 2026-02-27 09:54:18 +08:00
Merge pull request #34 from gaussmeter/feature-command
add support for teslamate logging resume/suspend
This commit is contained in:
@@ -96,6 +96,7 @@ Basically the same environment variables for the database, mqqt and timezone nee
|
||||
- **DATABASE_NAME** string *(default: teslamate)*
|
||||
- **DATABASE_HOST** string *(default: database)*
|
||||
- **MQTT_HOST** string *(default: mosquitto)*
|
||||
- **TESLAMATE_URL** string *(default: http://teslamate:4000)*
|
||||
- **TZ** string *(default: Europe/Berlin)*
|
||||
|
||||
**Optional** environment variables
|
||||
@@ -118,6 +119,7 @@ Basically the same environment variables for the database, mqqt and timezone nee
|
||||
- **ENABLE_COMMANDS** boolean *(default: false)*
|
||||
- **COMMANDS_ALL** boolean *(default: false)*
|
||||
- **COMMANDS_ALLOWLIST** string *(default: allow_list.json)*
|
||||
- **COMMANDS_LOGGING** boolean *(deafault: false)*
|
||||
- **COMMANDS_WAKE** boolean *(default: false)*
|
||||
- **COMMANDS_ALERT** boolean *(default: false)*
|
||||
- **COMMANDS_REMOTESTART** boolean *(default: false)*
|
||||
@@ -151,6 +153,8 @@ More detailed documentation of every endpoint will come..
|
||||
- POST `/api/v1/cars/:CarID/command/:Command`
|
||||
- GET `/api/v1/cars/:CarID/drives`
|
||||
- GET `/api/v1/cars/:CarID/drives/:DriveID`
|
||||
- PUT `/api/v1/cars/:CarID/logging/:Command`
|
||||
- GET `/api/v1/cars/:CarID/logging`
|
||||
- GET `/api/v1/cars/:CarID/status`
|
||||
- GET `/api/v1/cars/:CarID/updates`
|
||||
- POST `/api/v1/cars/:CarID/wake_up`
|
||||
@@ -159,7 +163,7 @@ More detailed documentation of every endpoint will come..
|
||||
|
||||
### Authentication
|
||||
|
||||
If you want to use command endpoints such as `/api/v1/cars/:CarID/command/:Command` and `/api/v1/cars/:CarID/wake_up`, you need to add authentication to your request.
|
||||
If you want to use command or logging endpoints such as `/api/v1/cars/:CarID/command/:Command`, `/api/v1/cars/:CarID/wake_up`, or `/api/v1/cars/:CarID/logging/:Command` you need to add authentication to your request.
|
||||
|
||||
You need to specify a token yourself (called **API_TOKEN**) in the environment variables file, to set it. The token has the requirement to be a minimum of 32 characters long.
|
||||
|
||||
|
||||
@@ -16,6 +16,13 @@ func initCommandAllowList() {
|
||||
// allow all commands available below
|
||||
allowAll := getEnvAsBool("COMMANDS_ALL", false)
|
||||
|
||||
// https://github.com/adriankumpf/teslamate/discussions/1433
|
||||
if getEnvAsBool("COMMANDS_LOGGING", false) || allowAll {
|
||||
allowList = append(allowList,
|
||||
"/logging/resume",
|
||||
"/logging/suspend")
|
||||
}
|
||||
|
||||
// https://tesla-api.timdorr.com/vehicle/commands/wake
|
||||
if getEnvAsBool("COMMANDS_WAKE", false) || allowAll {
|
||||
allowList = append(allowList, "/wake_up")
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
_ "github.com/lib/pq"
|
||||
)
|
||||
|
||||
// TeslaMateAPICarsLoggingCommandV1 func
|
||||
func TeslaMateAPICarsLoggingCommandV1(c *gin.Context) {
|
||||
|
||||
// creating required vars
|
||||
var jsonData map[string]interface{}
|
||||
var err error
|
||||
|
||||
// check if commands are enabled.. if not we need to abort
|
||||
if getEnvAsBool("ENABLE_COMMANDS", false) == false {
|
||||
log.Println("[warning] TeslaMateAPICarsLoggingCommandV1 ENABLE_COMMANDS is not true.. returning 403 forbidden.")
|
||||
c.JSON(http.StatusForbidden, gin.H{"error": "You are not allowed to access logging commands"})
|
||||
return
|
||||
}
|
||||
|
||||
// if request method is GET return list of commands
|
||||
if c.Request.Method == http.MethodGet {
|
||||
c.JSON(http.StatusOK, gin.H{"enabled_commands": allowList})
|
||||
return
|
||||
}
|
||||
|
||||
// authentication for the endpoint
|
||||
validToken, errorMessage := validateAuthToken(c)
|
||||
if !validToken {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": errorMessage})
|
||||
return
|
||||
}
|
||||
|
||||
// getting CarID param from URL
|
||||
ParamCarID := c.Param("CarID")
|
||||
var CarID int
|
||||
if ParamCarID != "" {
|
||||
CarID = convertStringToInteger(ParamCarID)
|
||||
}
|
||||
|
||||
// validating that CarID is not zero
|
||||
if CarID == 0 {
|
||||
log.Println("[error] TeslaMateAPICarsLoggingCommandV1 CarID is invalid (zero)!")
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "CarID invalid"})
|
||||
return
|
||||
}
|
||||
|
||||
// getting request body to pass to Tesla
|
||||
reqBody, err := ioutil.ReadAll(c.Request.Body)
|
||||
if err != nil {
|
||||
log.Println("[error] TeslaMateAPICarsLoggingCommandV1 error in first ioutil.ReadAll", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "internal"})
|
||||
return
|
||||
}
|
||||
|
||||
// getting :Command
|
||||
command := ("/logging/" + c.Param("Command"))
|
||||
log.Println("[debug] TeslaMateAPICarsLoggingCommandV1 command received:", command)
|
||||
|
||||
if !checkArrayContainsString(allowList, command) {
|
||||
log.Print("[warning] TeslaMateAPICarsCommandV1 command: " + command + " not allowed")
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
|
||||
return
|
||||
}
|
||||
|
||||
client := &http.Client{}
|
||||
putURL := getEnv("TESLAMATE_URL", "http://teslamate:4000") + "/api/car/" + ParamCarID + command
|
||||
req, _ := http.NewRequest(http.MethodPut, putURL, strings.NewReader(string(reqBody)))
|
||||
req.Header.Set("User-Agent", "TeslaMateApi/"+apiVersion+" https://github.com/tobiasehlert/teslamateapi")
|
||||
resp, err := client.Do(req)
|
||||
|
||||
// check response error
|
||||
if err != nil {
|
||||
log.Println("[error] TeslaMateAPICarsLoggingCommandV1 error in http request to http://teslamate:", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "internal"})
|
||||
return
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
defer client.CloseIdleConnections()
|
||||
|
||||
respBody, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Println("[error] TeslaMateAPICarsLoggingCommandV1 error in second ioutil.ReadAll:", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "internal"})
|
||||
return
|
||||
}
|
||||
json.Unmarshal([]byte(respBody), &jsonData)
|
||||
|
||||
// print to log about request
|
||||
if gin.IsDebugging() {
|
||||
log.Println("[debug] TeslaMateAPICarsLoggingCommandV1 " + c.Request.RequestURI + " returned data:")
|
||||
js, _ := json.Marshal(jsonData)
|
||||
log.Printf("[debug] %s\n", js)
|
||||
}
|
||||
|
||||
if resp.StatusCode == http.StatusOK || resp.StatusCode == http.StatusNoContent {
|
||||
log.Println("[info] TeslaMateAPICarsLoggingCommandV1 " + c.Request.RequestURI + " executed successful.")
|
||||
} else {
|
||||
log.Println("[error] TeslaMateAPICarsLoggingCommandV1 " + c.Request.RequestURI + " error in execution!")
|
||||
}
|
||||
c.JSON(resp.StatusCode, jsonData)
|
||||
}
|
||||
@@ -94,6 +94,10 @@ func main() {
|
||||
v1.GET("/cars/:CarID/drives", TeslaMateAPICarsDrivesV1)
|
||||
v1.GET("/cars/:CarID/drives/:DriveID", TeslaMateAPICarsDrivesDetailsV1)
|
||||
|
||||
// v1 /api/v1/cars/:CarID/logging endpoints
|
||||
v1.GET("/cars/:CarID/logging", TeslaMateAPICarsLoggingCommandV1)
|
||||
v1.PUT("/cars/:CarID/logging/:Command", TeslaMateAPICarsLoggingCommandV1)
|
||||
|
||||
// v1 /api/v1/cars/:CarID/status endpoints
|
||||
v1.GET("/cars/:CarID/status", TeslaMateAPICarsStatusV1)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user