In this guide I will describe the steps I took to automate the manual AC system in my FR-S using an Arduino Uno R3, a relay, a temperature sensor, a potentiometer and a 2 line LCD display.
Overview
The Arduino based system operates by measuring the ambient temperature using a LM35 temperature sensor and comparing that with a target temperature set using a potentiometer. If the ambient temperature is higher than 1 degree C from the target temperature the controller will cause the relay to switch the AC on. If the ambient temperature is lower than 1 degree C from the target temperature the controller will cause the relay to switch the AC off. This done approximately every 30 seconds to avoid cycling the AC too often.
If the target temperature potentiometer is turned either fully clockwise of anti clockwise the system will no longer control the AC. In this state the controller will simply display the ambient temperature.
Bonus feature
If you have a flex fuel kit installed and the kit provides a 0.5-4.5v signal indicating the ethanol content 0-100% the system can use this to calculate the current ethanol content of the fuel and add this information to the display.
Background
I am one of those people that hates to blend in hot air when the AC is on to maintain a desired temperature. It is a waste of energy and as a result, since I have never had a car with automatic climate control, I have had to manually turn the AC on and off. This is a nuisance that can be overcome with the aid of a simple controller.
While this write-up is specific to GT86, BRZ and FR-S vehicles with manual AC it can be used in all vehicles with manual AC. Also the instructions I give are specific to a 2013 FR-S and I take no responsibility for any damage to your car if you choose to follow my guide.
Hardware Parts list:
- Arduino Uno R3
- Arduino compatible relay
- LCD 1602
- LM35 temperature sensor
- 10K Ohm linear potentiometer
- 220 Ohm resistor
- 10K Ohm linear micro potentiometer
- 12v cigarette lighter to USB power adapter
- ~ 75cm USB to USB A cable
Note: most, if not all, of these components can be bought as part of an Arduino sensor starter kit available on eBay or Amazon.
Sundries:
- Insulated wire
- Heat shrink tubing
- solder
- soldering iron
Wiring
The following circuit diagram shows how I wired the sensors, relay and display together. Note 5V and ground are available on the Arduino board.
http://i.imgur.com/S04wYF3.png
Software Environment
I used Arduino software environment 1.6.9 running on a Mac. There are versions that run on other operating systems.
Code
The Arduino is quite straight forward to program. I have attempted to comment the code to describe how it functions. For those who are not familiar with the Arduino, two functions are all you really need to know: setup(), this is called once to initialize the system; loop(), this routine is called regularly by the supervisor code and this is where most of the controller is implemented.
Rather than explain the code line by line I would encourage you to study the code starting with the definitions of constants and global variables and the setup and loop functions.

Code:
/*
* Airconditioning Controller with Ethanol content display
*
* Author: Rob Esser
* Date: Version 1.0 5th of November 2016
*
* This SOFTWARE is provided "as is" and "with all faults."
* I make no representations or warranties of any kind concerning the safety, suitability, inaccuracies,
* typographical errors, or other harmful components of this SOFTWARE. There are inherent dangers in the
* use of any software, and you are solely responsible for determining whether this SOFTWARE is compatible
* with your equipment and other software installed on your equipment. You are also solely responsible
* for the protection of your equipment and backup of your data, and I will not be liable for any damages
* you may suffer in connection with using, modifying, or distributing this SOFTWARE.
*
* Resources used
* OpenSource 16x2 LCD display code from: http://www.arduino.cc/en/Tutorial/LiquidCrystal
* Watchdog timer code from https://bigdanzblog.wordpress.com/2014/10/24/arduino-watchdog-timer-wdt-example-code/
*
* The circuit:
* LCD RS pin to digital pin 12
* LCD Enable pin to digital pin 11
* LCD D4 pin to digital pin 5
* LCD D5 pin to digital pin 4
* LCD D6 pin to digital pin 3
* LCD D7 pin to digital pin 2
* LCD R/W pin to ground
* LCD VSS pin to ground
* LCD VCC pin to 5V
* 10K potentiometer: ends to +5V and ground, wiper to LCD VO pin (pin 3)
* Backlight LCD 15 to 220 Ohm resister to 5V
* LCD 16 to ground
*
* LM35 temperature sensor input analog pin 1
* Target temperature potentiometer input analog pin 2
* Ethanol fuel content input analog pin 4
* Relay output digital pin 10
*
*/
// include the library code:
#include <LiquidCrystal.h>
#include <avr/wdt.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
const int actualTempPin = 1; // Analog input 1
const int targetTempPin = 2; // Analog input 2
const int ethanolPin = 4; // Analog input 4 from flex fuel kit
const int relayPin = 10; // Digital Output 10
const int pinReadDelay = 10; // ms delay to stabilize reading on Arduino ADC when switching pin-to-pin?
const float TEMPDELTA = 1.0; // The amount of temperture hysteresis / 2
const float VOFF = 0.5; // The minimum voltage with 0% Ethanol
const float VRANGE = 4.0; // The active range of Ethanol values (0.5 - 4.5v)
bool relayState = false; // Keep track of the relay state
int iteration = 0; // the current iteration
const int windowSize = 5; // how many samples to average
int actualTemp[windowSize];
int actualTempIndex = -1;
int actualEthanol[windowSize];
int actualEthanolIndex = -1;
const int MAXITERATIONS = 29; // 0..29 at 1 second per iteration ~= 30 seconds
int analogReadWithDelays(int pin) {
analogRead(pin);
delay(pinReadDelay);
int val = analogRead(pin);
delay(pinReadDelay);
return val;
}
float getActualTemp() {
// get value from pin
int analogVal = analogReadWithDelays(actualTempPin);
// store in appropriate spot in window of values
int i;
if (actualTempIndex < 0) {
// First time just replicate first value
for ( i = 0; i < windowSize; i = i + 1 ) {
actualTemp[i] = analogVal;
}
actualTempIndex = 0;
} else {
// store the latest value
actualTemp[actualTempIndex] = analogVal;
// point to next value
actualTempIndex = (actualTempIndex + 1) % windowSize;
}
// get the sum of samples
int sum = 0;
for ( i = 0; i < windowSize; i = i + 1 ) {
sum += actualTemp[i];
}
// calculate the average
float average = float(sum) / windowSize;
// 10 bit A/D converter
float mv = (average / 1024.0) * 5000;
float cel = mv / 10;
return cel;
}
float getTargetTemp() {
int analogVal = analogReadWithDelays(targetTempPin);
// 10 bit A/D converter
float targetTemp = 0.0;
if ((analogVal > 10) and (analogVal < 1013)) {
// we have a range of 15-40 degrees C
targetTemp = (analogVal / 40.0) + 15;
}
return targetTemp;
}
//get the Ethanol value from the flex-fuel sensor (0.5 - 4.5v)
float getEthanol() {
int analogVal = analogReadWithDelays(ethanolPin);
// store in appropriate spot in window of values
int i;
if (actualEthanolIndex < 0) {
// First time just replicate first value
for ( i = 0; i < windowSize; i = i + 1 ) {
actualEthanol[i] = analogVal;
}
actualEthanolIndex = 0;
} else {
// store the latest value
actualEthanol[actualEthanolIndex] = analogVal;
// point to next value
actualEthanolIndex = (actualEthanolIndex + 1) % windowSize;
}
// get the sum of samples
int sum = 0;
for ( i = 0; i < windowSize; i = i + 1 ) {
sum += actualEthanol[i];
}
// calculate the average
float average = float(sum) / windowSize;
// 10 bit A/D converter
float v = (average/1024.0) * 5;
float eth = (v - VOFF) * 100.0 / VRANGE;
// Clamp the Ethanol value to be within 0..100%
if (eth < 0.0) {
eth = 0.0;
} else if (eth > 100.0) {
eth = 100.0;
}
return eth;
}
String getTempText(float degrees) {
String txt = "";
txt.concat(String(degrees, 0));
// Add in the degree symbol
txt.concat((char)223);
// Celcius
txt.concat("c");
if (degrees < 10.0) {
txt.concat(" ");
}
return txt;
}
String getEthanolText(float percent) {
String txt = " ";
txt.concat(String(percent, 0));
// Add enough characters to write to end of line
txt.concat("% ");
return txt;
}
/////////////////////////////////////////////////////////////////////////////////////
void setup() {
// immediately disable watchdog timer so set will not get interrupted
wdt_disable();
// the following forces a pause before enabling WDT. This gives the IDE a chance to
// call the bootloader in case something dumb happens during development and the WDT
// resets the MCU too quickly. Once the code is solid, remove this.
delay(2L * 1000L);
// enable the watchdog timer. There are a finite number of timeouts allowed (see wdt.h).
// Notes I have seen say it is unwise to go below 250ms as you may get the WDT stuck in a
// loop rebooting.
// Reasonable timeouts for this project are:
// WDTO_1S
// WDTO_2S
// WDTO_4S
// WDTO_8S
wdt_enable(WDTO_4S);
// Setup analog input pins (these are setup as inputs by default)
pinMode(actualTempPin,INPUT);
pinMode(targetTempPin,INPUT);
pinMode(ethanolPin,INPUT);
// initialize digital relayPin as the relay output.
pinMode(relayPin, OUTPUT);
digitalWrite(relayPin, LOW); // turn the LED/Relay OFF (LOW is the voltage level)
relayState = false;
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
// Print a message to the LCD.
lcd.setCursor(0, 0);
lcd.print("Rob's Climate ");
lcd.setCursor(0, 1);
lcd.print("Controller V1.0 ");
//A delay to make the welcome text visib;e
delay(2000);
}
void loop() {
//kick the (watch) dog
wdt_reset();
// Get analog values
float targetTemp = getTargetTemp();
float actualTemp = getActualTemp();
// get the Ethanol value from the flex-fuel sensor (0.5 - 4.5v)
float actualEthanol = getEthanol();
// Write data to the display
lcd.setCursor(0, 0);
if (targetTemp < 1.0) {
lcd.print(" ");
} else {
lcd.print("Target ");
lcd.print(getTempText(targetTemp));
}
//Now add in the Ethanol header to line 0
lcd.print(" Eth ");
// set the cursor to column 0, line 1
lcd.setCursor(0, 1);
lcd.print("Actual ");
lcd.print(getTempText(actualTemp));
lcd.print(getEthanolText(actualEthanol));
if (iteration >= MAXITERATIONS) {
// Only change relay state at most every 30 seconds
iteration = 0;
if (targetTemp < 1.0) {
relayState = false;
digitalWrite(relayPin, LOW);
} else if (actualTemp > (targetTemp + TEMPDELTA)) {
// Turn relay on
relayState = true;
digitalWrite(relayPin, HIGH);
} else if (actualTemp < (targetTemp - TEMPDELTA)) {
// Turn relay off
relayState = false;
digitalWrite(relayPin, LOW);
}
} else {
// Turn off immediately if we switch it off
if (targetTemp < 1.0) {
relayState = false;
digitalWrite(relayPin, LOW);
}
iteration ++;
}
// set the cursor to column 15, line 1
lcd.setCursor(15, 1);
// Now add an indication if the AC is on
if (relayState) {
lcd.print((char)62); // 62 = Arrow, 45 = minus sign
} else {
lcd.print(" ");
}
//wait a sec
delay(1000);
}
Gaining access to the AC Switch
To gain access to the AC switch you will need to dismantle the center console and the lower center section of the dash. It sounds more daunting than it actually is. I followed the excellent instructions at:
http://www.ft86club.com/forums/showthread.php?t=8336
Attaching the wires
Once you have access you will need to detach the plug from the temperature dial/AC switch assembly. The wires you are after are pin 2 (pink) and pin 3 (yellow). On the FR-S shorting these 2 pins together when the fan is on will turn the AC on. I carefully removed the insulation from each wire without cutting the wire and soldered a new wire sufficiently long to reach the handbrake (~ 50cm) to the exposed section of each. I then used shrink tubing to cover the bare wires and soldered joints to protect them and prevent shorts.
Unfortunately I forgot to take a photo showing how I attached the wires to the back of the AC switch / temperature dial - sorry.
Note: If you have an analog ethanol signal wire going to your ECU, also tap this wire and route it through the lower dash along with the other wires.
http://i.imgur.com/6TQnVFt.jpg

http://i.imgur.com/rvbZmKY.jpg
I chose to install the unit in the space made free by removing the small storage bin and the USB connector at the bottom of the center console.

http://i.imgur.com/4KmMek2.jpg
Creating a front panel
I cut a piece of aluminum to match the shape of the storage bin surround. I then cut a hole to fit the LCD display using a Dremel tool with a cutting wheel. I also drilled holes to mount the target temperature potentiometer and another hole to mount the LM35 temperature sensor in the upper left hand corner of the front panel. (not shown)

http://i.imgur.com/FlNziSa.jpg

http://i.imgur.com/AWVoRzb.jpg
The following photo shows the Arduino Uno with a prototype shield to mount the wiring and resistors. It also shows the relay board and the wiring to the front panel. I mounted the boards using cable ties to the base of a plastic container. This protects the circuit boards and fits snuggly into the space where the storage bin was located. The USB cable is then routed through the back of the center console and behind the glove box to a USB charger that plugs into the 12v socket in the glove box. This is a switched socket and has the advantage that if the software ever needs to be updated it is simply a matter of unplugging the USB cable from the socket and inserting it into a laptop.

http://i.imgur.com/QCUcjv4.jpg
Before installing the system into the car I tested it. As can be seen from the photo I covered the front panel with black faux carbon fiber vinyl. It improved the looks somewhat.

http://i.imgur.com/S7EVT1w.jpg
How the system looks when installed in the car.

http://i.imgur.com/EiD8yMn.jpg
Thanks