I made a button

Last winter was a cold one. Going into the phone app and turning the heater on is a known solution to help ensure maximum efficiency of the battery. With the winter coming soon, I wanted a better way to do it. Instead of the app, wouldn’t it be cool if I had a button to press that warmed my car up for me? I can leave it next to the dog’s leash so that when I walk her in the morning all I had to do is press the button and go about my business.

IMG_0058

Yeah, I know. The phone app works. Isn’t it good enough? No, that isn’t the point. I wanted to tinker and have some fun! I wanted to make a button with little lights and wires on a bread board. Besides, what would you rather do? Push a button or digg out your phone and go through that whole process? So, time to build a button.

I will say that this project was some of the more fun I’ve had with toys in a long time. I’ve never played with bread boards or programmed firmware before. I was surprised at how much documentation there is online and how well the DIY community has grown in the past few years now that the Internet of things is coming to fruition.

When looking for an internet button there are a lot of options to choose from.

  • Amazon Dash – https://aws.amazon.com/iot/button/
  • Flic – https://flic.io
  • Bt.tn – https://bt.tn

They each are designed to be simple to use and setup. Just go to their website and tell it what you want to do. But, they had some limitations. First, Flic goes through your cell phone. The point is to go away from the phone! The other buttons all use cloud services and I didn’t want to open my servers up to the internet for this. Once I found the Particle Photon (https://www.particle.io) I knew I had it… A gadget I can build and program from scratch. A true DIY project. I purchased mine from Sparkfun along with the breadboard wires and button and battery. The photon allows me to rewrite the device’s firmware with whatever code I want. So, instead of calling their API and going out to the internet, I simply call a program on a server in my lab.

Assembling the device was just a matter of taking the Photon, connecting it to the battery breakout board from Sparkfun, and putting that in a breadboard. I then connected the button following these instructions:

  • https://learn.sparkfun.com/tutorials/pull-up-resistors
  • http://www.instructables.com/id/Arduino-Button-Tutorial/

To sum them up I wired one of the digital pins to one leg of the button. And the other button leg to ground. When the button is pressed current flows to ground and the system will register it.

I’m going to skip going over the hard stuff and talk about the server code. Basically, the photon uses WIFI and sends a web request over to my lab server. The program does a bit of authentication (I pass a token from the button to the server that must be present for it to work). The meat of the script runs the following API commands (the Tesla API can be found here: http://docs.timdorr.apiary.io/#)


t = TeslaApi::Client.new(...snip...)
t.login!(...snip...)
begin
model_s = t.vehicles.first
rescue Exception => msg
log.puts "#{now} teslabutton.cgi FAILURE Unable to login to TeslaApi"
puts cgi.header( { status: 501 } )
exit
end
model_s.wake_up
model_s.auto_conditioning_start unless model_s.climate_state["is_auto_conditioning_on"]

As you can see I am logging all the calls to a file. The file is then read by my Splunk forwarder on the server and then I can alert on failure (yay error checking) and improper usage of my button.

OK, back to the tricky part… I told you that I had to rewrite the firmware for the button right? Well, this is the tough part. I can write tons of posts on all the various oops I made. Did you know leaving WiFi turned on kills your power? One problem I faced is due to how the Photon turns on. Pushing the button runs the same code as charging the battery for the first time. When I power the unit on I did not want to start my car! I only want it started when pushing the button. So after working with the Photon folks we are doubling what the button does so that the API only gets called if you are holding the button down when the Photon powers on. Here is the C++ code I currently use for the device.


#include "application.h"
#include "HttpClient.h"

// Sleep only until button press, so set a timeout so long as to not be
// relevent
#define forever 3153600000

// Dont be connecting to wifi automatically
SYSTEM_MODE(MANUAL);

// HTTP Request objects
HttpClient http;

http_header_t headers[] = {
{ "Accept", "*/*" },
{ NULL, NULL }
};

http_request_t request;
http_response_t response;

void setup() {
// Secondary LED
pinMode( D7, OUTPUT );
// Button
pinMode( D6, INPUT_PULLDOWN );
}

void start_wifi() {
// Start wifi up and connect to the network
WiFi.on();
WiFi.connect();
while (!WiFi.ready()) {
delay( 100 );
}
}

void do_work() {
start_wifi();

// Steal LED and let user know we're making the http call
RGB.control( true );
RGB.color( 0,0,255 ); // blue

// Make http call
request.hostname = "192.168.1.12";
request.port = 80;
request.path = "/teslabutton/?77ef7a64121e1a548d9c6e58e8e0611e";
http.get( request, response, headers );

// Let user know its done
RGB.color( 0,255,0 );

// Force a delay to ensure we don't execute the action constantly
delay(5000);
}

void loop() {
// Don't let our loop get called when photon is powered up.
// Only after button pressed. So look for the button press event
if ( digitalRead( D6 ) == HIGH ) {
// Let user know we read button press
digitalWrite( D7, HIGH );

// Do the API call
do_work();
}

// move the device into low power mode until button pressed
System.sleep( SLEEP_MODE_DEEP, forever );
}

Is it perfect? No. Like every DIY project there is plenty of room for improvement:

  • Battery life is abysmal. I have a 2000 mAh battery connected, and the thing only lasts a few days in sleep mode. I really want this to last weeks. Plus with the LED off I can’t tell if it asleep or out of juice until I push the button.I was able to fix this by using the Deep Sleep mode of the Photon. Deep sleep basically shuts it down with the exception of a timer and a power pin to power it back on. Supposedly it can go months without recharging… Lets find out. The new code is posted above.
  • I could probably put some more error checking in there to catch issues with the web call not working and alert me.
  • I would also like it to flash the LED to remind me if the car isn’t charging at night (I tend to forget to plug it in some nights).

So, keep watching and maybe I’ll post updates to make the button better.