Microcontroller projects

Radiator thermostat hacks

last updated: 06/10/19

Introduction

Back in 2010 we used HR20 thermostats from Honeywell (Rondostat) for a school project. They contained an ATmega169 controller from Atmel, and a team from microcontroller.net hacked the thermostat and published the results (in German). Especially their pdf on the hardware revealed many interesting information. The thermostat has a 10 pin header with JTAG for programming, a GPIO Pin (PE2) and a serial interface.

We reprogrammed the thermostat with Bascom (Basic for AVR) and used the serial interface to communicate with the thermostat.

With new techniques like LoRaWan and ESP chips I think re-hacking would be interesting :).

Homeexpert by Honeywell Rondostat style

I have some old thermostats, but thought to look if the thermostat still exists, and for sure I found the same model with a rounder design. It is called homeexpert by Honeywell Rondostat style. To hack something the first challenge is always to open it without damaging the housing. First the big wheel can be removed with a screwdriver and by pulling hard. Than the two pieces of the axes are pulled apart (picture bottom). Now two of the fittings can be pushed with a screwdriver to pull off the display with the buttons.


Rondostat style

And for shure, the circuit seems to be the same as 9 years ago with an ATmega169 :)).


Rondostat style PCB front Rondostat style PCB back

How to program with Arduino

To program we need a JTAG programmer. I still have my old Dragon board from Atmel (now microchip), that is supported by avrdude used by Arduino. Another AVR JTAG programmer should do the same thing.

Her is the circuit of a little adapter board to connect the Dragon board to the thermostat.


avr dragon jtag adapter

Now we need an hardware core to use with Arduino. Fortunately MCUdude did already some work and we can download the core (.zip) at: https://github.com/MCUdude/ButterflyCore

Make a folder called hardware in your sketchbook folder. In the hardware folder you have a vendor folder with the vendor name and in this folder the architecture folder (here avr). So we get a portable/sketchbook/hardware/weigu/avr/ and uncompress the zip file here. Now we find the ATmega169 under Butterfly boards. We add the following lines to programmers.txt:

    dragon.name=Atmel AVR Dragon in JTAG mode
    dragon.communication=usb
    dragon.program.tool=avrdude
    dragon.protocol=dragon_jtag

I also had to exchange in line 222 of boards.txt the atmega169p with atmega169 and copied a more recent avrdude.conf to the folder. After this restart Arduino.

The file pins_arduino.h in /portable/sketchbook/hardware/weigu/avr/variants/standard/ tells us what numbers Arduino uses for the pins:

AVR pin 0 1 2 3 4 5 6 7
PA 44 43 42 41 40 39 38 37
PB  8  9 10 11 12 13 14 15
PC 28 29 30 31 32 33 34 35
PD 18 19 20 21 22 23 24 25
PE  0  1  2  3  4  5  6  7
PF 45 46 47 48 49 50 51 52
PG 26 27 36 16 17 - - -

We get 53 digital pins and 8 analog pins (PF0-PF7 as A0-A7).

With avrdude we can read the lock and fuse bits:

    cd arduino/arduino-1.8.10/hardware/tools/avr/bin
    ./avrdude -C../etc/avrdude.conf -v -patmega169 -cdragon_jtag -U lock:r:"lock.out":r
    ./avrdude -C../etc/avrdude.conf -v -patmega169 -cdragon_jtag

We must read the file lock.out with an hex editor and see that the lock bits are 0xFC or 0b1111101, so LB1 and LB2 are programmed: Further programming and reading of the Flash and EEPROM are disabled.

And we get: lfuse 0x62, hfuse 0x91 and efuse 0xFD.

lfuse 0x01100010 means:

hfuse 0x10010001 means:

efuse 0x11111101 means:

So we choose 1 MHz internal clock and the right brown out level (1.8 V) to program the board.


Arduino tools screen

Let's test it with a blink sketch for the external GPIO Arduino digital pin 2 (PE2):

    void setup() {
      init_gpio();
    }

    void loop() {
      gpio_low();
      delay(500);
      gpio_high();
      delay(500);
    }

    void init_gpio() {
      pinMode(2, OUTPUT);
    }

    void gpio_low() {
      digitalWrite(2, LOW);
    }

    void gpio_high() {
      digitalWrite(2, HIGH);
    }

Don't forget to press shift to use the external programmer to upload the sketch.

Yes! it works!

To change fuses you can use (e.g. no clock divide by 8), but pay attention to not brick the device (JTAG disabled):

./avrdude -C../etc/avrdude.conf -v -patmega169 -cdragon_jtag -U lfuse:w:0xE2:m

Testing the Hardware

Motor

Now lets turn the motors. We need the following Arduino pins: 12 (PB4), 15 (PB7), 16 (PG3) and 17 PG4:

  12 15 16 17
STOP 0 0 0 0
OPEN 1 0 1 0
CLOSE 0 1 0 1
    void setup() {
      init_motor();
    }

    void loop() {
      motor_open();
      delay(3000);
      motor_close();
      delay(3000);
      motor_stop();
      delay(13000);
    }

    void init_motor() {
      pinMode(12,OUTPUT);
      pinMode(15,OUTPUT);
      pinMode(16,OUTPUT);
      pinMode(17,OUTPUT);
    }

    void motor_close() {
      digitalWrite(12,LOW);
      digitalWrite(15,HIGH);
      digitalWrite(16,LOW);
      digitalWrite(17,HIGH);
    }

    void motor_open() {
      digitalWrite(12,HIGH);
      digitalWrite(15,LOW);
      digitalWrite(16,HIGH);
      digitalWrite(17,LOW);
    }

    void motor_stop() {
      digitalWrite(12,LOW);
      digitalWrite(15,LOW);
      digitalWrite(16,LOW);
      digitalWrite(17,LOW);
    }
Switch "thermostat mounted"

The switch "thermostat mounted" 8 (PBO) is closed if thermostat is not mounted! We use an internal pull up resistor.

    void setup() {
      init_switch_tm();
      init_motor();
    }

    void loop() {
      if (switch_tm()) {
        motor_open();
      }
      else {
        motor_stop();
      }
    }

    void init_switch() {
      pinMode(8, INPUT_PULLUP);
    }

    bool switch_tm() {
      return digitalRead(8);
    }
User commands

We get three push-buttons and 2 inputs from the our rotary pulse encoder.

    void setup() {
      init_rotary();
      init_motor();
    }
    /********** LOOP **********************************************************/

    void loop() {
      if (rotary() == 0x01) {
        motor_open();
        delay(100);
      }
      if (rotary() == 0x10) {
        motor_close();
        delay(100);
      }
      motor_stop();
    }

    void init_rotary() {
      pinMode(13, INPUT_PULLUP);
      pinMode(14, INPUT_PULLUP);
    }

    byte rotary() {  // 0-3: AUTO|MANU = 4 °C = 2 PROG = 1
      return (digitalRead(13)*2+digitalRead(14));
    }
reflection sensor

Honeywell Home evohome THR092HRT

I thought it possible that Honeywell uses Atmel chips in newer devices and bought a Honeywell Home evohome THR092HRT and jackpot! We get USB and an ATmega644. Hopefully we can hack the thing and program our own RF thermostat.