-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit d9e23d6
Showing
6 changed files
with
487 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
*.o | ||
*.a | ||
*.so | ||
|
||
*.out | ||
*.html | ||
*.test | ||
*.prof | ||
*.stackdump | ||
*.exe |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
// | ||
// Brett Morrison, Februrary 2016 | ||
// | ||
// A program to alert if Tesla is not plugged in at a specified GeoFence | ||
// | ||
package main | ||
|
||
import ( | ||
"TeslaCommand/lib/HaversinFormula" | ||
"TeslaCommand/lib/VehicleLib" | ||
"flag" | ||
"fmt" | ||
"os" | ||
"time" | ||
) | ||
|
||
// Magic clientid and clientsecret available here: http://pastebin.com/fX6ejAHd | ||
const clientid = "e4a9949fcfa04068f59abb5a658f2bac0a3428e4652315490b659d5ab3f35a9e" | ||
const clientsecret = "c75f14bbadc8bee3a7594412c31416f8300256d7668ea7e6e7f06727bfb9d220" | ||
|
||
var teslaLoginEmail string | ||
var teslaLoginPassword string | ||
var vehicleIndex int | ||
var geoFenceLatitude float64 | ||
var geoFenceLongitude float64 | ||
var mailServer string | ||
var mailServerPort int | ||
var mailServerLogin string | ||
var mailServerPassword string | ||
var fromAddress string | ||
var toAddress string | ||
var radius int | ||
var checkInterval int | ||
|
||
func init() { | ||
flag.StringVar(&teslaLoginEmail, "teslaLoginEmail", "", "Email for teslamotors.com account") | ||
flag.StringVar(&teslaLoginPassword, "teslaLoginPassword", "", "Password for teslamotors.com account") | ||
flag.IntVar(&vehicleIndex, "vehicleIndex", 0, "Index of vehicles in your account - If just 1 vehicle, use 0") | ||
flag.Float64Var(&geoFenceLatitude, "geoFenceLatitude", 0.0, "Latitude of GeoFence Center") | ||
flag.Float64Var(&geoFenceLongitude, "geoFenceLongitude", 0.0, "Longitude of GeoFence Center") | ||
flag.StringVar(&mailServer, "mailServer", "", "SMTP Server hostname") | ||
flag.IntVar(&mailServerPort, "mailServerPort", 25, "SMTP Server port number") | ||
flag.StringVar(&mailServerLogin, "mailServerLogin", "", "SMTP Server login username") | ||
flag.StringVar(&mailServerPassword, "mailServerPassword", "", "SMTP Server password") | ||
flag.StringVar(&fromAddress, "fromAddress", "", "Alert send from email") | ||
flag.StringVar(&toAddress, "toAddress", "", "Alert send to email") | ||
flag.IntVar(&radius, "radius", 0, "Radius in meters from center geoFence - Typically use 200") | ||
flag.IntVar(&checkInterval, "checkInterval", 5, "Time in minutes between checks for geoFence") | ||
} | ||
|
||
func main() { | ||
fmt.Printf("Num Args %d\n", len(os.Args)) | ||
flag.Parse() | ||
if len(os.Args) != 14 { | ||
flag.Usage() | ||
os.Exit(1) | ||
} | ||
|
||
var li VehicleLib.LoginInfo | ||
err := VehicleLib.TeslaLogin(clientid, clientsecret, teslaLoginEmail, teslaLoginPassword, &li) | ||
if err != nil { | ||
fmt.Println(err) | ||
os.Exit(1) | ||
} | ||
fmt.Println("token: " + li.Token) | ||
|
||
var vir VehicleLib.VehicleInfoResponse | ||
err = VehicleLib.ListVehicles(li.Token, &vir) | ||
if err != nil { | ||
fmt.Println(err) | ||
os.Exit(1) | ||
} | ||
|
||
// Need to set this flag for every time vehicle exits and enters GeoFence (so we don't send repeated alerts) | ||
ingeofence := false | ||
|
||
// Loop every N minutes. | ||
fmt.Printf("Waiting to check vehicle %v location for %v minutes...\n", vir.Vehicles[vehicleIndex].DisplayName, checkInterval) | ||
for _ = range time.Tick(time.Duration(checkInterval) * time.Minute) { | ||
fmt.Printf("Checking vehicle %v location after waiting %v minutes.\n", vir.Vehicles[vehicleIndex].DisplayName, checkInterval) | ||
|
||
var vlr VehicleLib.VehicleLocationResponse | ||
err = VehicleLib.GetLocation(li.Token, vir.Vehicles[vehicleIndex].ID, &vlr) | ||
if err != nil { | ||
fmt.Println(err) | ||
os.Exit(1) | ||
} | ||
|
||
distance := HaversinFormula.Distance(geoFenceLatitude, geoFenceLongitude, vlr.VehicleLocation.Latitude, vlr.VehicleLocation.Longitude) | ||
|
||
fmt.Printf("Distance: %v\n\n", distance) | ||
|
||
// If the distance is outside the radius, that means vehicle is outside the GeoFence. Ok to get out | ||
if distance > float64(radius) { | ||
ingeofence = false | ||
} | ||
|
||
// This is to prevent the below logic, if it's already executed, no need to keep doing it | ||
if ingeofence == true { | ||
continue | ||
} | ||
|
||
// In the GeoFence. Get the vehicle charge state. | ||
var vcsr VehicleLib.VehicleChargeStateResponse | ||
err = VehicleLib.GetChargeState(li.Token, vir.Vehicles[vehicleIndex].ID, &vcsr) | ||
if err != nil { | ||
fmt.Println(err) | ||
os.Exit(1) | ||
} | ||
|
||
// Check if the vehicle is stopped. | ||
if vlr.VehicleLocation.Speed == 0 { | ||
//Check if the vehicle is plugged in. | ||
if vcsr.VehicleChargeState.ChargingState == "Disconnected" { | ||
// Disconnected, stopped, and within the radius - send alert | ||
ingeofence = true | ||
subject := "Tesla Command - " + vir.Vehicles[vehicleIndex].DisplayName | ||
body := fmt.Sprintf("Vehicle is within %v meters of GeoFence with a battery level of %v percent. Please plug in.", int(distance), vcsr.VehicleChargeState.BatteryLevel) | ||
fmt.Println(body) | ||
err = VehicleLib.SendMail(mailServer, mailServerPort, mailServerLogin, mailServerPassword, fromAddress, toAddress, subject, body) | ||
if err != nil { | ||
fmt.Println(err) | ||
os.Exit(1) | ||
} | ||
} | ||
} | ||
fmt.Printf("Waiting to check vehicle %v location for %v minutes...\n", vir.Vehicles[vehicleIndex].DisplayName, checkInterval) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
// Package HaversinFormula ... | ||
// | ||
// Pulled from gist: https://gist.github.com/cdipaolo/d3f8db3848278b49db68 | ||
// | ||
package HaversinFormula | ||
|
||
// haversin(θ) function | ||
import "math" | ||
|
||
func hsin(theta float64) float64 { | ||
return math.Pow(math.Sin(theta/2), 2) | ||
} | ||
|
||
// Distance function returns the distance (in meters) between two points of | ||
// a given longitude and latitude relatively accurately (using a spherical | ||
// approximation of the Earth) through the Haversin Distance Formula for | ||
// great arc distance on a sphere with accuracy for small distances | ||
// | ||
// point coordinates are supplied in degrees and converted into rad. in the func | ||
// | ||
// distance returned is METERS!!!!!! | ||
// http://en.wikipedia.org/wiki/Haversine_formula | ||
func Distance(lat1, lon1, lat2, lon2 float64) float64 { | ||
// convert to radians | ||
// must cast radius as float to multiply later | ||
var la1, lo1, la2, lo2, r float64 | ||
la1 = lat1 * math.Pi / 180 | ||
lo1 = lon1 * math.Pi / 180 | ||
la2 = lat2 * math.Pi / 180 | ||
lo2 = lon2 * math.Pi / 180 | ||
|
||
r = 6378100 // Earth radius in METERS | ||
|
||
// calculate | ||
h := hsin(la2-la1) + math.Cos(la1)*math.Cos(la2)*hsin(lo2-lo1) | ||
|
||
return 2 * r * math.Asin(math.Sqrt(h)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package VehicleLib | ||
|
||
import ( | ||
"fmt" | ||
"net/smtp" | ||
"strconv" | ||
) | ||
|
||
// SendMail ... | ||
func SendMail(mailServer string, mailServerPort int, mailServerLogin string, mailServerPassword string, fromAddress string, toAddress string, subj string, body string) error { | ||
// Set up authentication information. | ||
auth := smtp.PlainAuth("", mailServerLogin, mailServerPassword, mailServer) | ||
|
||
// Connect to the server, authenticate, set the sender and recipient, and send the email in one step. | ||
to := []string{toAddress} | ||
msg := []byte("To: " + toAddress + "\r\nSubject: " + subj + "\r\n\r\n" + body + "\r\n") | ||
serverPort := mailServer + ":" + strconv.Itoa(mailServerPort) | ||
fmt.Printf("Sending mail via server %s\n", serverPort) | ||
err := smtp.SendMail(serverPort, auth, fromAddress, to, msg) | ||
if err != nil { | ||
return fmt.Errorf("sendMail error: %s", err) | ||
} | ||
|
||
return nil | ||
} |
Oops, something went wrong.