Ethernet AC Interface (Part 9)
I really like my Ethernet AC Controller. Its probably the most useful thing I’ve built. So when I decided to give PCB manufacturing a try, it was a good candidate for an upgrade. This post covers the (re)design and features of my new Ethernet AC controller. If you haven’t read my other posts, my goal here was to be able to control my air conditioner from my cellphone.
Besides simply moving from perf-board to a printed circuit board, I had a couple other goals: I wanted to build/design/code everything myself, and I wanted a better IR communications dialect. With the exception of a few shortcuts, I pretty happy with reaching these goals.
You can find my previous documentation on the IR communication of my AC here. I’ve figured out a lot since writing that post. Most of what I learned came from this universal remote. Instead of having simple buttons for “Up/Down”, this remote has an LCD with the current temperature displayed. This means instead of sending “Up/Down” signals, this remote has to send “Set Temperature to 70″. Even better the remote also sends “On” and “Off” instead of “Toggle power.” This was great since my previously known commands, “Power Toggle”, “Temperature Up/Down” were of limited usefulness when trying to control the air conditioner away from home.
I hooked the new remote up to an oscilloscope and yanking out the codes. I stared at the raw captures for a long time, and eventually sorted out the physical layer. It looks the same as in my previous post, but I’ve interpreted it very differently. Data is transmitted with a carrier of 38khz with a 50% duty cycle. A “unit of time” is defined as 1/38,000 of a second.
- LED is illuminated for 344 units of time
- LED is off for 172 units of time
- At this point data is transmitted MSB
- Each bit is framed by illumination for 22 units of time.
- If transmitting a 0, the LED stays off for 23 units of time.
- If transmitting a 1, the LED stays off for 68 units of time.
- The light is illuminated for 22 units of time, and we go back to step 7 if there’s more data to send.
I spent considerable time making sure I was correctly understanding the physical layer. This was critical to being able to construct custom IR commands, and calculate correct check-sums.
Once I defined the physical layer correctly, figuring out the data protocol was easy. Data is transmitted in 24 bits plus a 4 bit checksum:
IIII IIII SSSS SSSS TTTT RRFF CCCC Where: I - always 0x88 (the unit id?) S - always 0x00 to turn the unit and set mode to "cool" other values in the field include "dehumidify", but I didn't document them T - is the desired temperature. 0x1 being coolest, 0xF the warmest in increments of 1 degree Celsius. R - reserved (or rather, I don't know, but sent as 0x0) F - fan speed (low = 0x0, med= 0x2, high = ox4) C - a 4 bit check some of all other data
If you have an AC with the same physical layer, but data transmission is completely different, the code / project may still be of used. If you compile with -D SUPPORT_RAW_COMMAND it’s possible to to use the web server to send raw binary commands over the IR transmitter using the physical protocol described above. For example, the following turns my AC off: http://myac/cgi-bin/ac/raw/1C88C00510. 0x1C is the length of transmission in bits. 0x88c00510 is the data transmitted, including the check-sum.
The entire process of signal generation, and command construction can be found here: lg.c. See the top of the file for the predefined IR commands, and lg_create_command() for building an IR op-code for specific temperature and fan speed.
I decided on trying the WIZnet W5100. This decision worked well for a couple reasons. First, I could easily prototype software on an Arduino + WIZnet shield setup. I’ve never used the Arduino tool-chain, but as a hardware platform for verifying my firmware before integrating with my PCB it worked great.
Second, the W5100 meant I wouldn’t have to try to implement TCP/IP like an ENC28J60 based project. Really, the only problem with the W5100 was its 0.4mm pitch on the leads (which was out-of-spec for BatchPCB). The W5200 solves this problem, but it doesn’t support SPI, and I wasn’t ready to try my hand at routing memory access bus. I was left with no choice but to use a break-out board .
MCU selection was pretty easy, I went with an ATmega328 (although the code will fit on an 8K part too, depending on compiled features). I picked up Atmel parts when I started years ago because of the stronger Linux support. I stayed in the 88/168/328 line to ease any issues porting the code form Arduino.
I think after about 2 weekends of work, I managed to layout my PCB. It was my first experience creating a circuit board. I used this tutorial to get started, plus some other resources which I forgot to bookmark.
It took a few tries to get right, and months of waiting for delivery, but here’s the final version:
Assembly was a lot easier than expected. Some of the parts are really small, but as long as I used a generous amount of flux the solder flowed where it was needed and wicked up easily. For harder to solder parts, or if I was just lazy, I switched to lead solder.
This was only my second or third time using surface mount parts. I’ve found tweezers, flux, wick, temperature controlled iron, and magnifier the only required tools. SMT is getting a lot easier with each attempt. I’m a lot faster now, and rarely have problems with part alignment.
Here’s revision 1 (left) and 2 (right). Only one “green wire” on my very first PCB!
What Didn’t Work
In system programming
The W5100 seems to have trouble when initially powered on. Even on the Adruino shield it failed. I fixed the shield by adding a 0.1uf cap to the reset pin. For my PCB, I simply wired reset to a GPIO pin on the AVR. I figured if the problem did show up, be able to fix it in software.
But, I didn’t pay close enough attention to the SPI bus. PCB Rev 1 had problems with in-system-programming (ISP) of the AVR. Since the W5100′s reset was controlled by software, I could not hold it in reset while ISP routines were running and as a result it was driving MISO. PCB Rev 2 fixed this by adding tri-state buffers to the W5100 and uSD card. Under normal operation the buffers default MISO to HiZ unless CS is active. I also added somewhat strong pull-up resistors (10k) to make sure the buffers remained HiZ while the AVR was held in reset.
I had redesign the PCB a few times because I built around parts that weren’t in stock. Even parts I thought would be no trouble to find, like a 2×9 2mm header just didn’t exist.
I added a temperature sensor to the board, an MCP9800. I thought it would be neat to build some graphs on temperature trending, but it turned out to not work at all. Although the software and I2C interface were fine, the board ran slightly warm, so I couldn’t get ambient temperature readings.
I drive the IR LED with 20 ma (the maximum source current of the AVR), but it is not bright enough to cover range of more than a few feet. Next time I’ll add a transistor.
To control the AC i have two interface: first I can simply type the AVR’s ip address into a web browser and use a GUI, and second there is an API interface: http://air.conditioner/cgi-bin/ac/on?temp=74&fan=1
I’m not really happy with the performance of the software, maximum download speeds are ~20-30kbytes/second. This is more then fast enough for my application, but there’s definitely room to make things faster (but, probably at the expense of reuse and readability).
Source and Design Files
I wrote almost all the code myself, with only one exception. The board is also a webserver, reading content off of a FAT uSD card. Support for uSD and FAT come from elm-chan.
Eagle PCB Files & Gerbers: https://github.com/braiden/embedded-ac-controller/tree/master/pcb
Source Code: https://github.com/braiden/embedded-ac-controller
Parts List: http://www.mouser.com/ProjectManager/ProjectDetail.aspx?AccessID=8c0f0b4605
Circuit Board: http://batchpcb.com/index.php/Products/36530
See LICENSE. Feel free to try to build one yourself, or re-purpose the design.
More to Come
I still want to implement a nice android widget for controlling the AC.