W1209 Data Logging Thermostat

The W1209 thermostat is cheap, but it's about time that it learns new tricks!

Similar projects worth following
W1209 thermostats are incredibly cheap (below $1.50), and so "easy" to use that there about 30.000 YouTube videos that explain how to "program" one. This project is here to change that: using STM8 eForth the behavior of the board can be scripted. In fact, only a serial terminal program is needed to write a new program!

This project turns a W1209 into a thermostat with a programming console, and a data logger feature. It provides easy to follow instructions, and also gives a gentle introduction to Forth.

Features are:

  • heating thermostat, e.g. for building a chicken egg incubator
  • no special tool installation necessary:
    • ready-made binaries, and source code, are provided
    • new binaries can be built with the help of Travis-CI
    • interactive programming in Forth, even while the thermostat task is running!
    • any serial terminal program can be used, e.g. picocom, or cutecom (settings 9600-N-8-1)
  • data logger with 6 minutes (0.1h) to 10h interval, and a 144 entry ring-buffer with log access through a serial console:
    • Lowest temperature
    • Highest temperature
    • Heating duty cycle
    • Number of relay cycles
    • L.dump command prints the log through the serial console - the latest entry is in the last line
    • L.wipe command erases the log memory
  • basic sensor failure detection
  • easy to use parameters menu (no need to search for a manual!) for set-point, hysteresis, and trip-delay

  • 1 × W1209 Your favorite low cost thermostat unit!
  • 1 × USB-RS232 dongle with TTL interface CH340, FTDI, Prollific, or old cell phone cable. Should be compatible with 5V signals.
  • 1 × ST-Link V2 adapter Cheap if you're ready to wait for one to arrive from China. The cable that usually comes with it can be cut iin the middle and used to make the ICP and the serial port connections :-)

  • More-or-Less Compatible W1209 Clones

    Thomas02/09/2018 at 20:11 0 comments

    A GitHub user documented a W1209 clone with a common anode display. This issue describes how to spot such a clone, and it also contains code patched for using the CA display. This board will be supported in the near future.

    I found one more clone with a different PCB layout, and I ordered one for examination.

  • Which W1209 boards *not to buy* if you want to run the code here

    Thomas01/31/2018 at 20:11 0 comments

    @richard got a couple of W1209 boards, and some of them just couldn't be flashed. It turns out the at least one manufacturer (namely TENSTAR ROBOTS) makes boards with a nearly pin compatible 8051 based µC (a Nuvoton chip in a TSSOP20 package). Details are at the end of the GitHub Issue here.

    Mitigation: don't buy boards that look like one of these:

    Note that C5, the Vcc capacitor next to the µC, is unpopulated. The backside of the black board is bears the label "TENSTAR ROBOT W1209". The label on the back of the green board is "XH-W1209". The Nuvoton is quite fast, and if you like programming the 8051 it's maybe not the worst choice. However, please don't count on my help for programming it. I'm done with MCS51 ;-)

    @BigVulcanDeal let me know that there are boards with a 5k, instead of 20k, reference resistor. That's a good match for measuring temperatures in the range of 30°C to 50°C, but you'll need to replace the linearization table in measure.fs.

  • Release 0.2.0: improved Data Log, better Sensor Filtering

    Thomas12/17/2017 at 10:24 0 comments

    I've just release a new, improved version of the W1209 Data Logging Thermostat: now the data logger registers the following data:

    • relay activation cycles per log interval
    • relay duty cycle
    • lowest, and highest temperature in the cycle

    Used properly, this data can be used to improve the control behavior (heating power), or for getting clues on the effects of heat flow & thermal mass, sensor location, or quality of the insulation:

    w1209-log2Check out the README on Github for features, source, and instructions!

  • Temperature Logging with the W1209

    Thomas12/10/2017 at 09:45 0 comments

    By default, the firmware exploits the fact that the Value Line STM8S003F3 µC is just a STM8S103F3 with relaxed specs, and with only 128 bytes of EEPROM memory specified. All the chips I tested hat the full 640 bytes of the "Access Line - Low Density Devices" available, and I decided to use all but 64 bytes as a ring buffer, enough for more than 24 hours at a rate of 10 samples per second.

    The ring buffer requires a single head pointer, which, for practical reasons, must be in the EEPROM. The number of EEPROM write cycles of Value Line devices, however, is specified with 1x10^5, in the full temperature range with nominal data retention, that is. At a rate of 10 log entries per hour a 20ct µC is still good for 10.000 hours, more than a year.

    I have little doubt (not "little doubts", like my Indian colleagues usually say when the strongly disagree) that the number of write cycles at room temperature, and with random data, is more in the range of 1x10^6, more than 10 years. The "electrical life" of a Chinese low-end relay in a thermostat application is most likely much shorter.

  • Minimal Viable Product

    Thomas11/26/2017 at 16:41 0 comments

    There is finally the the first (pre-) release of the W1209 $1.50 data logging thermostat!

    It's based on the latest STM8 eForth (pre-release 2.2.20.pre.1), and the binary was automatically built in uCsim, and deployed, by Travis-CI.

    Features are:

    • heating thermostat, e.g. for building chicken egg incubators
    • basic sensor failure detection
    • parameters for set-point, hysteresis, and trip-delay
    • easy to use parameters menu (no need to search for a manual!)
    • temperature logger with 0.1h to 10h interval, and a 288 entry ring-buffer
    • logger access through a serial console
    • fully programmable in Forth, even while the thermostat is running!

    Although it's feature-complete, it's work in progress.

    For the future, the following feature are planned:

    • Improved logger with min/max temperature, and heating duty cycle
    • Field-bus feature for thermostats
    • more fail-safe features (parameter integrity, maybe a buzzer)

  • Dependencies up-to-date: the Makefile now installs STM8 eForth

    Thomas11/04/2017 at 18:57 0 comments

    It's been a while since I last worked on this little project. The reason was that I concentrated on the STM8 eForth foundations:

    • development framework with a Forth library
    • e4thcom support
    • with emulation of the e4thcom features #include, #require, and \res
    • automatic generation of "aliases" for unlinked words in STM8 eForth words
    • Continuous Integration/Test/Deployment with Travis-CI

    The GitHub W1209 repository now also uses these goodies, and the Makefile automatically installs the specified revision of STM8 eForth from the binary release.

  • A scripting language for a thermostat

    Thomas08/10/2017 at 06:28 0 comments

    This project builds a scripting language for W1209 thermostats. The scripting language is Forth based, but that doesn't mean that you need to know much Forth to get something done (the goal is that you don't need to know it's Forth).

    To do achieve this, I'm experimenting with a simple "processing" pattern: chained steps.

    \ background task with temperature control
    : task ( -- )
      measure            \ measure temperature
      control            \ temperature control
      logger             \ data logging
      menu               \ menu and display code

    The trick is that, like in jQuery, one can chain "filters" if the data type of "output" matches the "input". In the case of a thermostat that's easy: it's all about temperature.

    The other part is that chainable filters are self-contained units. To do this I use basic modular programming techniques, and a chained init function:

    \ chained init - starting point
    : init ( -- )
    #include measure.fs
    #include control.fs
    #include logger.fs
    #include menu.fs

    In a module, e.g. measure, the initialization looks like this:

    \ chained init
    : init ( -- ) init
      \ init LPF state with max. value
      dig2temp2 DUP @ 1- 2* 1+ + @ LPFDIG !

    The word init first calls the init word of the previous module, and the complicated part, e.g. filter initialization, is nicely hidden.

    The next thing is the file include hierarchy, a design feature of e4thcom. The file search path is: "cwd:cwd/mcu:cwd/target:cwd/lib" (cwd = current working directory). The standard filter words for an application are in the target folder. In an application, library words can be transparently replaced with a modified version without the need to change the library.

  • W1209 Sensor Properties

    Thomas08/07/2017 at 06:25 0 comments

    I made a first write-up about some findings on the NTC and the W1209 sensor input. The datasheet referenced by @jeff1937 doesn't match, and it would be nice to learn more about the particular NTC used for Chinese thermostats!

    Edit: I updated the Wiki page above: Chinese NTC sensors sometimes have the tag MFA52AT. I found a datasheet that that describes a typical W1209 sensor pretty well (error within 3%).

    Grades of 1%, 2%, and 5% of such sensors are common which means that you one should be careful when commissioning a thermostat for applications where keeping a precise temperature is necessary (e.g. chicken incubator, sous-vide cooking).

  • Example application: a Basic Incubator Thermostat

    Thomas08/06/2017 at 16:41 0 comments

    The repository on GitHub now contains a very simple thermostat for a chicken incubator (apparently that's a very popular application for the W1209).

    The core of the program is really simple:

    \ background task with temperature control
    : btask ( -- )
      measure            \ measure temperature
      DUP .0 CR          \ print it
      TEMPLIMIT < OUT!   \ keep temperature stable

    The word btask runs in the 5ms background cycle. Forth transfers most data through the data stack (just like a RPN calculator), which is great for concatenating commands! measure performs sensor reading and linearization, leaving a temperature value on the stack (in units of 0.1 °C). DUP duplicates the value for .0 which prints it as ##.#, ###, or -##. CR is just a newline. For the thermostat function the remaining value on stack needs to be compared with TEMPLIMIT (e.g. 375 for 37.5°C). If the 1st value on the stack is smaller than the 2nd, < results in -1 (0b1111111111111111), or else 0. OUT! copies "all ones" or "all zeros" to all the available outputs (which happens to be just one relay). That's all, no condition structure (e.g. IF..THEN) was required. Check out incubator.fs, measure.fs, and inter.fs on GitHub. The whole program consists of just 113 lines of code including linearization, two level filtering, and formatted output.

    Of course, one would should probably add some kind hysteresis. But then again, why not go for a PID controller? Yes, that's possible with a relay as the control output.

    As for the "definition of done" of the initial user story:

    • ☑ Thermostat function with programmable, but fixed temperature threshold
    • ☑ 3 digit temperature display
    • ☑ bonus: key can be operated while the serial connection works
    • how-to instructions, and a ready to use binary
    • data logging every 10 minutes

    Data logging will be next. Of course without a RTC "10 minutes" will be "about 10 minutes", but I'm sure that it won't be too difficult to work around this on the PC side.

View all 9 project logs

  • 1
    Set Parameters

    Press "set", and use the "+" and "-" keys to navigate the menu. Press "set" again to edit a parameter. Store with "set", or wait about 10s until the menu times out.

  • 2
    Apply the Thermostat with the help of the Data Logger

    Install the thermostat in your installation, as you would with the original firmware. The sometimes difficult task of optimizing the control behavior can be simplified by using logged data. Refer to the README for instructions.

  • 3
    Prepare the W1209

    Follow the instructions on the STM8 eForth W1209 wiki page to erase the original W1209 firmware, and program the thermostat binary in the file on the W1209 data logging thermostat releases page. After flashing, make sure it starts up (the display should show the temperature, or "DEF." if no sensor is connected. To initialize the parameters in the EEPROM press the W1209 "+" and "-" keys for about 5 seconds ("RES." should appear).

View all 3 instructions

Enjoy this project?



BigVulcanDeal wrote 02/01/2018 at 04:49 point

I made a simple Google Docs spreadsheet that can be used to calculate the values for the dig2tem table if you have a "non-standard" pull-up resistor for the sensor.  Enter the resistor value in k-ohms in cell A2, copy the dig2tem values from M2:M15.  The digtem values will be about right .. then use the correction parameter to tune for best performance at the temperature range of interest.

  Are you sure? yes | no

BigVulcanDeal wrote 01/18/2018 at 06:32 point

I managed to install stm8flash and loaded the Dec 17th binary on my W1209, but the temperature is slightly ridiculous .. it shows up like -5.9 degrees.  Is there an easy way to correct this?  

As an aside, amazing project .. haven't used Forth in quite some time (well over 20 years).

  Are you sure? yes | no

BigVulcanDeal wrote 01/18/2018 at 06:39 point

Also, L.dump seems to print continuously.  Is this how it is supposed to work?

I will hunt around to see if I can answer my own questions .. you managed to put a lot of material together.

  Are you sure? yes | no

Thomas wrote 01/24/2018 at 19:27 point

Writing more stuff is faster than improving what's already there. If you find something that's hard to find, or that's not clear and needs better explanation, please let me know.

  Are you sure? yes | no

BigVulcanDeal wrote 01/19/2018 at 03:46 point

I guess this is a matter of changing the dig2tem array to map to the actual sensor that I have ... apparently this RTD, or the resistor used with it, is different.

Apart from the temperature weirdness, the flashed board seems to work properly.

  Are you sure? yes | no

BigVulcanDeal wrote 01/19/2018 at 05:09 point

So, I found that my W1209 has a 5.2 K resistor where most have a 20k resistor.  This is good from the standpoint that it makes the sensor more sensitive at the temperatures that I care about .. however, I am unclear on how to get the source for the latest W1209-FD, build it from scratch, and then flash the board.  Once I know how to do that, I can tweak the dig2tem array.  When I clone the repository and make all, I end up with what seems to be a generic FORTH image on the board.

  Are you sure? yes | no

BigVulcanDeal wrote 01/20/2018 at 02:51 point

And the answer is .. make load

  Are you sure? yes | no

Thomas wrote 01/24/2018 at 19:33 point

Building from scratch should work. Alternatively you can fetch version 2.2.20 from the tg9541/stm8ef Github releases page (you need the board variant W1209-FD in the zip file). However, the Makefile in the tg9541/W1209 repository resolves the dependencies for you when you run "make depend". Finally, if you just use the thermostat binary file you just need to run "reset" on the command line to remove the Forth application code. If you do that from e4thcom you only need to run "#i main.fs" to load your code.

  Are you sure? yes | no

BigVulcanDeal wrote 01/22/2018 at 03:58 point

After a bit of floundering, I managed to 

- flash the board, 

- figure out about "make load", 

- alter the code in measure.fs to change the dig2tem table to handle a 5k resistor for the RTD (as opposed to the 20 k resistor presumes in the script)

- add accessor functions that allow me to read/write the various EE values (EE.SET etc.)

The only issue remaining is that I was unable to get logger.fs to load .. so I just commented it out, along with the call to "logger' within "task"

  Are you sure? yes | no

Thomas wrote 01/24/2018 at 19:24 point

Hi, sorry, for some reason I didn't receive notifications about your posts!

I'm surprised about the 5K resistor, and it's good that it's now known that there are hardware variants on the market (which, of course complicates using the board).

It's good to see that you figured out how to load the code. I'd like to figure out why loading the last part of the code doesn't work. Did you try using e4thcom?

  Are you sure? yes | no

Thomas wrote 01/24/2018 at 20:57 point

After removing ".S" from line logger.fs line 18 uploading the file should work. The problem is due to the e4thcom feature "ignore debug output" missing in

The code in the GitHub repository has been updated!

  Are you sure? yes | no

BigVulcanDeal wrote 01/24/2018 at 21:39 point

Awesome!  Thanks Thomas!

  Are you sure? yes | no

Thomas wrote 01/27/2018 at 09:25 point

@BigVulcanDeal : issue #17 tracks changes (docs, software) required for the hardware variant. If you find the time, fork the W1209 thermostat repo and add your changes (e.g. new lookup table). I would also like to know more about the source of your W1209.

  Are you sure? yes | no

darko.lombardo wrote 12/10/2017 at 20:34 point

Hi Thomas.

I have uploaded the latest W1209-FD binary to W1209 board and attached USB/UART dongle to +/- buttons.

I get to the console at 9600bps.

How can I use it as temperature logger, I mean how to read the temperature on a PC?

  Are you sure? yes | no

darko.lombardo wrote 12/10/2017 at 21:13 point

I am able to use the logger:

1. "L.wipe<ENTER>" to wipe all the logger data and restart the minute counter

2. set logger period in LoG display menu to 0.1 (~ 6 min)

3. Read log using "L.dump<ENTER>" - all 288 entries from oldest reading (1) to newest reading (288)

But the W1209 does the measurements much more frequently and displays the result on the LCD.

How can I get the last (current) temperature value using serial console?

  Are you sure? yes | no

Thomas wrote 12/17/2017 at 11:11 point

Hi Darko,

Sorry, I didn't notice your message! I've added some features in the meantime, but I didn't realize that someone might actually need to use the temperature on the console :-)

Please try the following Forth definition:

: theta lpf.tem2 @ 2/ .0 ;

If you just want to use it as a temperature reader, you can of course strip the current software down. In that case you only need the following in the main.fs:

#include measure.fs
#include menu.fs
\ #include logger.fs
\ #include control.fs
: task ( -- )
  \ the application runs as a background task
  measure ( -- theta ) \ measure temperature
  \ logger ( theta -- theta ) \ data logging
  \ control ( theta -- theta ) \ temperature control
  menu ( theta -- theta ) \ menu and display code

Using uploading Forth code to the W1209 should also be possible under Windows. With Travi-CI you can build a new firmware even with a tablet PC!

Please write an GitHub Issue if you have a feature request.

  Are you sure? yes | no

Eelco wrote 09/30/2017 at 14:52 point

I had problems to upload files to the board with e4thcom and the stm8ef-release of  this projects repository (v2.2.13) so I flashed it with v2.2.16, BOARD=W1209-FD. This works fine. I really like these stm8ef projects. And the e4thcom support is a big improvement.

My experience with this board is that it is reasonable accurate in the 25 C range but at high temperatures it is not.  This is due to the fact that  at high temperatures  a change in temperature results in a tiny voltage difference (about 5C per 5V/1024) so the ADC is hardly capable of detecting temperature changes. I once put the censor in boiling water and the reading exceeded 110C hence error. I plan to use a  mindev board and multiple voltage deviders for the NTC to be able to switch for different temperature ranges. I think that would improve the resolution.

  Are you sure? yes | no

Thomas wrote 10/06/2017 at 18:54 point

Hi Eelco, you're right, at higher temperature the W1209 is inaccurate. Due to the a 20k pull-up resistor the NTC is best matched around 0 degC. An 1k pull-up resistor would match the NTC at 100 degC. I think that the optimum is somewhere in between, e.g. 3k. The "W1209 Sensor" page in the Wiki contains a table with the sensor values.

  Are you sure? yes | no

RigTig wrote 08/06/2017 at 10:58 point

And who better to teach the W1209 than this author. What a good use case to hack, and agile is the way to go. Cheap hardware and the addition of some smart software gives this project the opportunity for lots of variations, as other use cases arise.

  Are you sure? yes | no

Thomas wrote 08/06/2017 at 21:20 point

Thanks RigTig, you nailed it! Besides, this author learned quite a bit from you!

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates