Automating IR AC/Heater with Raspberry Pi and Google

Objective

Automate my existing apartment climate control system by adding a remote web interface to pre-cool my room on my way home during the summer and easy scheduling to warm my room before getting out of bed in the winter.

AC interface

Most Japanese air conditioner/heater units use IR controls incompatible with Nest so controlling over IR was the only option. Unfortunately reverse engineering the IR protocol would prove to be challenging. These IR remotes are completely different than those for TVs and other appliances. Most IR remotes send single commands like "on" or "volume up" but these AC units are stateless, it's the remote that has the brains, so each time a button is pressed the remote will send the entire list of settings values.  For instance, if you just press the button to increase temperature+1 say from 24 to 25, the remote will actually send [power:on, mode:heater, temp:25, air-speed:2, air-diffuser:on, timer:off...] I won't go into details but to say that this is clever engineering and UX given age of these systems, limitations of IR, and cost of alternatives.

Sadly, that complex IR protocol is difficult to parse and replicate so it would be alot of effort to create a granular controller from scratch. I may come back to that at some point but for now I found a simpler solution.

Since the remote stores the full state I could easily hijack an existing remote, set desired settings, then remotely "press" the on/off button over the web via relay. This is fine since I only change the settings twice a year in spring and fall from heater to cooler. Old used remotes can be found for about 500 yen ($4.50) and it only took a few seconds to trace the button contacts to the solder points.

Disassembled AC remote showing solder pins

Raspberry Pi

There are cheaper ways to trigger a relay but I bought a PiFace long ago for projects like this but never got around to using it until now. Unfortunately the PiFace library on the latest Raspbian Stretch has not been updated so I  recommend using Raspbian Jessie for now.

PiFace connected to AC remote

After installing Raspbian, configuring raspi-conig etc. the PiFace Python3 libraries can be installed as follows:

sudo apt-get install vim python3-pifacedigitalio

Below is the webserver script. Excuse my code as this is my first attempt at Python. Be sure to change the toggle key as this should be unique.

import pifacedigitalio
import time
import os.path
import sys
import ssl
from http.server import BaseHTTPRequestHandler, HTTPServer
from urllib.parse import urlparse, parse_qs

# Bind interface and port. 0.0.0.0 = all interfaces
BIND_IP = '0.0.0.0'
BIND_PORT = 8000

# Key to obfuscate the URL. Change this to something unique
TOGGLE_KEY = 'abc123'

class GetHandler(BaseHTTPRequestHandler):

    def do_GET(self):

        # Send HTTP headers
        self.send_response(200)
        self.send_header('Content-type',
                         'text/plain; charset=utf-8')
        self.end_headers()
       
        self.state = self.get_state()
        # http message to user
        message = "AC appears to be " + self.state + "\r\n"

        # Get URL query string parameters as dict
        params = parse_qs(urlparse(self.path).query)

        # Validate request
        if 'key' in params and params['key'][0] == TOGGLE_KEY:
            if 'set' in params:
                if params['set'][0] == self.state:
                    message += "Doing nothing\r\n"
                else:
                    self.toggle()
                    # Append output message
                    message += "Toggling AC\r\n"
                    message += "AC should now be " + self.state + "\r\n"
        
        # Write output message to http
        self.wfile.write(message.encode("utf-8"))

    # Save state to file. Either "on" or "off"
    def set_state(self, newstate):
        statefile = open(os.path.join(sys.path[0], 'state.txt'), 'w+')
        statefile.write(newstate)
        statefile.close()
        self.state = newstate
        print('AC switched ' + newstate)
    
    # Read state from file
    def get_state(self):
        statefile = open(os.path.join(sys.path[0], 'state.txt'), 'r')
        readstate = statefile.read() 
        statefile.close()
        return readstate    
    
    # Toggle state. Momentary close relay + update state file
    def toggle(self):
        pfd = pifacedigitalio.PiFaceDigital()
        pfd.relays[0].value = 1
        time.sleep(0.5)
        pfd.relays[0].value = 0
        if self.state == 'on':
            self.set_state('off')
        else:
            self.set_state('on')

# HTTP server
if __name__ == '__main__':
    server = HTTPServer((BIND_IP, BIND_PORT), GetHandler)
    # Comment out this line to disable SSL
    server.socket = ssl.wrap_socket(server.socket, keyfile='/home/pi/key.pem', certfile='/home/pi/cert.pem', server_side=True)
    print('Starting server, use <Ctrl-C> to stop')
    server.serve_forever()

One major caveat is that this is a unidirectional control with no feedback from the IR remote nor AC main unit so it's impossible to know for sure if all systems are in sync but it's unlikely for the Pi and connected remote control to get out of sync which is the most important part as the remote will always clobber the AC base unit state.

Once the script is running, the AC can be turned on/off by the following URLs:
 https://example.com:8000/?set=on&key=<your key>
 https://example.com:8000/?set=off&key=<your key>

Obviously you'll want to setup port forwarding in your router to gain remote access. I'd strongly advise against using any well-known port as those will be heavily scanned.

Scheduling 

Cron seemed like an obvious solution but the interface is not designed for dynamic schedule changes. Writing a scheduling system in Python was another option but again not worth the effort.

Google Calendar provides a great interface but after reading the API documentation it wasn't looking good. Calendar supports push notifications but only on event change, not event start. Calendar could send emails on event start but would require an email server. What I really needed was a way for Calendar to send an HTTP GET request then it hit me!


IFTTT supports Google Calendar event triggers and URLs as an actions. I connected IFTTT to a new Google calendar called "aircon" and created new "applets" which wait for events with text "on" or "off" and open the corresponding URL.



Android ad-hoc control

I was thinking or writing a small Android app, and may still, but Chrome makes it easy to add URL shortcuts to your Android home screen so there's really no need. URL shortcuts make turning the AC on/off literally one click.

Update: Now with voice control

Turns out IFTTT also supports Google Assistant as a trigger so now I can just have Google Assistant on my phone or Google Home turn the heater on/off as needed in addition to the calendar scheduling.

Future features

The system is working well for now but when time permits I plan to further enhance the system.
  • Power off when I leave the house based on pinging my phone on WiFi
  • Enabling geofencing to turn on automatically when I'm on my way home
    • This could be tricky since I often eat, shop, and work within 1km of home
  • Temperature monitoring to confirm state

Parts and pricing

I had most parts laying around but if you were to buy these parts here's what they'd cost.
Total cost ~$60

Popular posts from this blog

Simple Raspberry Pi Interval Camera with Google Drive Upload

Updated Raspberry Pi Timelapse Camera with Google Drive Upload

Loose Link Pins on the Huawei Watch (hwatch) Band