From 9b2970ee4b2ed164694a0ae61fd65c728ee3064f Mon Sep 17 00:00:00 2001 From: Tim Dorr Date: Wed, 22 Jun 2016 00:10:08 -0400 Subject: [PATCH] Initial autopark client support. See #16 for more details. --- lib/tesla_api.rb | 13 ++++---- lib/tesla_api/autopark.rb | 62 +++++++++++++++++++++++++++++++++++++++ lib/tesla_api/vehicle.rb | 1 + lib/tesla_api/version.rb | 2 +- tesla_api.gemspec | 42 +++++++++++++------------- 5 files changed, 91 insertions(+), 29 deletions(-) create mode 100644 lib/tesla_api/autopark.rb diff --git a/lib/tesla_api.rb b/lib/tesla_api.rb index ad7fd943..2f662854 100644 --- a/lib/tesla_api.rb +++ b/lib/tesla_api.rb @@ -1,7 +1,8 @@ -require "httparty" -require "em-http-request" +require 'httparty' +require 'em-http-request' -require "tesla_api/version" -require "tesla_api/client" -require "tesla_api/stream" -require "tesla_api/vehicle" +require 'tesla_api/version' +require 'tesla_api/client' +require 'tesla_api/stream' +require 'tesla_api/autopark' +require 'tesla_api/vehicle' diff --git a/lib/tesla_api/autopark.rb b/lib/tesla_api/autopark.rb new file mode 100644 index 00000000..eaf507b0 --- /dev/null +++ b/lib/tesla_api/autopark.rb @@ -0,0 +1,62 @@ +require 'faye/websocket' + +module TeslaApi + module Autopark + def start_autopark(&handler) + EventMachine.run do + socket.on(:message) do |event| + message = if event.data.is_a?(Array) + JSON.parse(event.data.map(&:chr).join) + else + JSON.parse(event.data) + end + + default_handler(message) + handler.call(message.delete('msg_type'), message) + end + + socket.on(:close) do |_| + @socket = nil + @heartbeat && @heartbeat.cancel + EventMachine.stop + end + end + end + + private + + def default_handler(message) + case message['msg_type'] + when 'control:hello' + interval = message['autopark']['heartbeat_frequency'] / 1000.0 + @heartbeat = EventMachine::Timer.new(interval) do + beat = { + msg_type: 'autopark:heartbeat_app', + timestamp: Time.now.to_i + } + socket.send(beat.to_json) + end + end + end + + def socket + @socket ||= Faye::WebSocket::Client.new( + socket_endpoint, + nil, + { + headers: { + 'Authorization' => "Basic #{socket_auth}" + } + } + ) + end + + def socket_auth + Base64.strict_encode64("#{email}:#{self['tokens'].first}") + end + + def socket_endpoint + "wss://streaming.vn.teslamotors.com/connect/#{self['vehicle_id']}" + end + end +end diff --git a/lib/tesla_api/vehicle.rb b/lib/tesla_api/vehicle.rb index 234c0a4f..ad522a93 100644 --- a/lib/tesla_api/vehicle.rb +++ b/lib/tesla_api/vehicle.rb @@ -1,6 +1,7 @@ module TeslaApi class Vehicle include Stream + include Autopark attr_reader :api, :email, :id, :vehicle def initialize(api, email, id, vehicle) diff --git a/lib/tesla_api/version.rb b/lib/tesla_api/version.rb index 6c1da078..982e665b 100644 --- a/lib/tesla_api/version.rb +++ b/lib/tesla_api/version.rb @@ -1,3 +1,3 @@ module TeslaApi - VERSION = "1.2.0" + VERSION = '1.2.0' end diff --git a/tesla_api.gemspec b/tesla_api.gemspec index d9a9f5b7..d8569532 100644 --- a/tesla_api.gemspec +++ b/tesla_api.gemspec @@ -1,32 +1,30 @@ -lib = File.expand_path('../lib', __FILE__) -$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) -require 'tesla_api/version' +require File.expand_path('../lib/tesla_api/version', __FILE__) Gem::Specification.new do |spec| - spec.name = "tesla_api" + spec.name = 'tesla_api' spec.version = TeslaApi::VERSION - spec.authors = ["Tim Dorr"] - spec.email = ["timdorr@timdorr.com"] + spec.authors = ['Tim Dorr'] + spec.email = ['timdorr@timdorr.com'] spec.summary = %q{A wrapper for the Tesla API} spec.description = %q{Check the state of your Tesla Model S and issue basic commands. Stream data from the car's telematics system.} - spec.homepage = "https://github.com/timdorr/model-s-api" - spec.license = "MIT" + spec.homepage = 'https://github.com/timdorr/model-s-api' + spec.license = 'MIT' - spec.files = `git ls-files -z`.split("\x0") - spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } + spec.files = `git ls-files -z`.split("\0") spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) - spec.require_paths = ["lib"] + spec.require_paths = ['lib'] - spec.add_dependency "httparty" - spec.add_dependency "em-http-request" + spec.add_dependency 'httparty' + spec.add_dependency 'faye-websocket' + spec.add_dependency 'em-http-request' - spec.add_development_dependency "bundler", "~> 1.7" - spec.add_development_dependency "rake", "~> 10.0" - spec.add_development_dependency "rspec", "~> 3.1" - spec.add_development_dependency "faker", "~> 1.4" - spec.add_development_dependency "vcr", "~> 2.9" - spec.add_development_dependency "webmock", "~> 1.20" - spec.add_development_dependency "dotenv", "~> 1.0" - spec.add_development_dependency "simplecov", "~> 0.9" - spec.add_development_dependency "coveralls" + spec.add_development_dependency 'bundler', '~> 1.7' + spec.add_development_dependency 'rake', '~> 10.0' + spec.add_development_dependency 'rspec', '~> 3.1' + spec.add_development_dependency 'faker', '~> 1.4' + spec.add_development_dependency 'vcr', '~> 2.9' + spec.add_development_dependency 'webmock', '~> 1.20' + spec.add_development_dependency 'dotenv', '~> 1.0' + spec.add_development_dependency 'simplecov', '~> 0.9' + spec.add_development_dependency 'coveralls' end