ESP8266 IoT room thermometer – part 1

Impulsiveness is not always a good thing. So here’s a handy rule for you: first, prototype; then fabricate the PCBs. Doing it that way, things have a chance of going well. Reverse that order and … well, not so much.

Not that it was a disaster. In fact I had prototyped this little project – mostly. But we’re getting ahead of ourselves.

Wifi loveliness

There was a period when forums were constantly a-twitter with talk of the ESP8266, the miracle microcontroller with built-in wifi loveliness. And for a long time I mostly ignored it because I was busy elsewhere. Then I gave in and ordered a fewthe Adafruit Huzzah board, to be precise, because I trust Adafruit. I mucked about with MicroPython and thought, ‘this is rather nice’, then put it aside to concentrate on other stuff.

The prototype. The ESP8266 board is pushed into female headers soldered to a prototyping board. This also has tactile buttons mimicking the two buttons on the ESP8266 which I find very awkward to press. The whole thing is mounted alongside a breadboard on an acrylic base. This allows for easy experimentation.

But over winter I found myself with a need to know the temperature in my office. It wasn’t just a desire. I really needed this information.

As someone who suffers from osteoarthritis, I’m somewhat sensitive to temperature. If it drops too low, the pain in my joints increases notably.

Now, I could have just bought a digital thermometer (actually, I bought two) and set it up at my workstation. But where’s the fun in that? No, I wanted a thing – as in the Internet of Things (IoT).

So I dug out the ESP8266 boards and looked around for a suitable temperature sensor. I had a few lying around, but when I tried using them and compared the results with a digital thermometer I found they were somewhat inaccurate.

Eventually I settled on the DHT22. And then I learned a lesson. I bought a few, very cheap, from China via eBay. Not only didn’t they agree with the digital thermometer, they didn’t even agree with each other. It’s possible they were rejects. Then I bought a few more at slightly higher cost from reputable suppliers. These were consistent in readings, although still half a degree Celsius below the digital thermometer. I can live with that. And although it’s unlikely the error is linear across the full range of temperatures, within the limited range I’ll be experiencing in my office I should be able to just add a 0.5ºC compensation in the software if I want.

The sensor has four pins – VCC, GND, data out and one that isn’t used. You pull the data pin high with a resistor (I used a 10kΩ), attach it to a GPIO pin and then use the Adafruit library. Easy.

(BTW, I developed the code for this project in the Arduino IDE, in its usual dialect of C.)

As a display I opted for a 2.2in SPI-driven 240×320 TFT panel that I’ve used a lot with the Teensy with great success. I’m controlling this with the Bodmer TFT_eSPI library which provides for lots of nice fonts and easy text placement, once you get used to it.

The display shows the current temperature, rounded to the nearest integer (in Celsius, because I’m European and have forgotten why anyone bothers with Fahrenheit). Under that is the actual temperature to one decimal place, the minimum and maximum temperatures since the last reset (more on this in a moment) and the relative humidity.

Then come the time and date. Underneath those is a three-line area for various messages, including one just for errors. These messages disappear after a certain period (which is set in the code). Finally, there’s a line at the bottom showing the SSID of the wifi access point in use and the ESP8266’s IP address.

Time & date

I didn’t want to add a real-time clock. It was just too much complication and besides, the Huzzah board almost certainly wouldn’t have enough GPIO pins to accommodate it. To hell with that anyway because this is an Internet thing. If it wants to know the time it can just ask a server.

In terms of electronic components, then, there isn’t a lot more than the three main items – the ESP8266 board, the TFT LCD display and the temperature sensor. I needed a couple of resistors – one to pull the data line on the DHT sensor high and one to limit the current for the power supply to the screen’s backlighting. I also decided to add a reset button, so I added another resistor to pull that high too.

In spite of the simplicity, though, I decided to have a PCB made. It would save on a lot of wiring and would be smaller than, say, a stripboard solution. Besides, having started to get comfortable with KiCad I just like making PCBs now.

That’s when things got a little wobbly.

Mission creep

While drawing up the schematic I noticed I had three spare pins. Pin 0 on the Huzzah is a bit weird, being associated with the bootloader, so I decided to ignore that. But pins 15 and 16 were also unused.

This was about the same time I decided the display should show maximum high and minimum low temperatures. And I wanted a way of resetting that. No problem – I’ll add a second ‘reset’ button. Pin 15 seemed handy. I’ll pull that high with a resistor and then set up an interrupt to watch for it being pulled low, I thought.

Remember, this is after I’d built the breadboard prototype and while I was drawing the schematic. I was pretty confident it would work, so I went ahead and laid out the PCB and ordered 10 of them from a fab house (total cost $9 including shipping).

Then I added the new button to the breadboard prototype.

It didn’t work.

I’ll save you the agonies I went through. It turns out that pin 15 is also a bit weird on this board. According to Adafruit it is, “used to detect boot-mode. It has a pulldown resistor connected to it, make sure this pin isn’t pulled high on startup. You can always just use it as an output”. Damn. I couldn’t even upload new versions of the code to the ESP8266 board because I had this pulled high.

I switched to pin 16, but couldn’t get the interrupt to fire. So I tried pin 2. That worked with the interrupt, but on my board it’s tied up for use with the temperature sensor. I considered changing lots of pin assignments, but the thought was somewhat daunting.

Polling

In the end I redesigned the schematic and board layout and reworked the software to use pin 16 with simple polling, rather than using an interrupt. I still don’t know why the interrupt doesn’t work, but assume it’s somehow connected to the fact that the pin is used to wake the microcontroller from deep sleep.

I hadn’t considered polling before for one good reason – my original version of the code included a long delay (six seconds no less) in the main loop. This is because the device isn’t in any hurry to do anything. The main loop does the following:

  • Checks in with a server to update the time and date – once a minute is enough for this.
  • Checks in with a server to send the current temperature and humidity, so the server can log them and display the data on our intranet. A side-effect of this is checking the wifi connection is still good. Once every five or 10 minutes is good enough for this.
  • Checks and displays the current temperature and humidity – I figured five-minute intervals are good enough for this.

So I used a six-second delay in the loop and integer counters to decide when these actions should take place. That made polling for button pushes very haphazard because the processor was spending most of its time in a delay() function!

To sort that, I divided the delay time by 10 and multiplied the limits for the counters by the same factor to compensate. Now the delay time is 600 milliseconds – just over half a second. This works well because when you press the button to reset the min/max values there’s that slight delay before it happens. You have to be very deliberate about it, which I think is a good thing in a reset button. Also, the delay debounces the switch.

The PCBs I ordered should still work, I just won’t solder in the headers for the min/max reset button and the associated pullup resistor. If I want to reset the minimum and maximum values I’ll just reset the whole shebang with the main reset button.

In the next part I’ll talk about how it talks with the server.

» Read Part 2 »

19 thoughts on “ESP8266 IoT room thermometer – part 1

  1. Richard P

    Done a similar toy, but different mission requirement. The DHT11 is a dismal device and much like you, I went with the DHT22. I still didnt trust the DHT so I also added the DS18B20 1Wire temperature sensor as a belt-and-braces. Connectivity was via MQTT to a server, but I dont think its a good idea to keep a device running just to serve the temperature. My next version will have its own web server and dish out JAVASCRIPT to I can see the history. For power failure modes, a supercap and some code to detect the input voltage being unstable triggered a SPIFFS write of the history data before it shut itself down. All data was timestamped as the ESP8266 synced to a NTP clock.

    I wanted an outdoor sensor, so I built it all in to a PVC tube. As a radio amateur, I have a mast that has power points so getting power outdoors is an easy task.

    Reply
    1. Machina Post author

      Hadn’t thought of using NTP for the clock – I think I’ll look into that.

      Reply
  2. Daniel Fernandes

    Sure, a really cool project, but I couldn’t see the arduino sketch in any of the three parts; Could you share the sketch or sketches?
    Thank you very much

    Reply
    1. Machina Post author

      This is not an easy one to share. The reason is the display stuff. I use the TFT_eSPI library and, within that, defined a bunch of custom fonts. The library also needs some configuration. The TFT_eSPI library is a bit of a bugger. Whenever you update it, it wipes out your custom fonts and settings. (I’ve taken to saving those in another location and re-copying them over after each update.) So, long story short, you can’t just take my code and run it. I’ll think about a way of sharing my setting etc, but bear in mind you *will* need to do some tinkering. Check back in a day or so and I’ll let you know whether I’ve been able to throw this up on GitHub.

      Reply
        1. Daniel Fernandes

          Hi Machina, First, thanks for sharing your sketch; I have some questions:
          1) Regarding the files ‘User_Setups’ and ‘User_Setup’, no problem.
          2) I also set SSID and Password in HomeWifi folder > HomeWifi file.
          3) I load the code (normal) and show the following on the display: -Trying: Dancopy (my network), so I ask: should I change anything in the sketch, like here? #define HTTP_SERVER
          Any tips, please? (Live in Brazil)
          Thank you very much

          Reply
          1. Machina Post author

            It should at least log on to your wifi AP, so check you have the password correct (it’s case sensitive). The HTTP_SERVER is for communication with the REST API server that sends the device the time, date etc. And the device reports temperature back to the server. If it fails to communicate with a server, it should just produce a blank time and date.

  3. Daniel Fernandes

    Hi Machina! I may be repeating this text, but I did not find it in the comments section of your page.
    If I’m bothering you, simply don’t answer me ok?
    So am I on the right track? However, if I am wrong, I can not know where, therefore, I even checked the HomeWifi.h folder, checking the SSID and Password. (I put the password as it is on my router)
    Here: #define HTTP_SERVER http://10.0.0.159/iotServer.php I left it as it is because I don’t know if I should change; I simply use ADSL internet with router and WiFi works normally.
    Again I say: on the screen it still shows: Connecting to wifi … -trying: Dancopy for about 30 seconds and goes blank as it finds nothing. Weird!!
    Is this not about the REST API or HTTP_SERVER above?
    Note: I have other sketches with WiFi and it works normally.
    I would love to use your sketch because I found the design beautiful.
    If you can give me some more tips, thank you very much,
    Daniel

    Reply
    1. Machina Post author

      The wifi connection and REST API should be two separate things. It sounds like you’re failing to connect to your wifi AP for some reason.

      Where have you put the HomeWifi.h file? I should be in a folder called HomeWifi which, in turn, should be in the Arduino/libraries folder.

      What are the contents of this file?

      The way this works is that it looks for two APs. First it tries the main one and, if connection to that fails, it tries the alternative one. If that fails it goes back to the main one and so on. It will try each AP WIFI_MAX_TRIES times (set to 12 in my sketch). The fact that you’re seeing only one attempt is odd. It feels like it’s somehow crashing or stalling in the ‘while (connect_counter < WIFI_MAX_TRIES)' loop within the wifiConnect() function. The URL defined for HTTP_SERVER is that of a PHP script on my home intranet server - obviously that's not going to work for you! You'll need to roll your own server script.

      Reply
  4. Daniel Fernandes

    Hi Machina! I continue to thank you for your answers and patience with me!
    Yes, he performs the 12 attempts; then find nothing and stop.

    The HomeWifi file is in this path: C: \ Users \ Daniel \ Documents \ Arduino \ libraries \ HomeWifi

    Content:
    #define HOME_WIFI_AP_MAIN “Xxxxxxx” // as on router
    #define HOME_WIFI_AP_ALT “Xxxxxxx” // as on router
    #define HOME_WIFI_PW “xxxxxxxxxxx” // as on router

    I have two internet in my home: ADSL and Fiber Optic; I already tried with both, one at a time, putting the respective password but it does not work with either.

    Already tried with two ESP8266 Nodemcu (working) – NOTHING!

    I’m assuming it must be something in the sketch (code), because it looks for the network (and the password is correct!)

    If you can take a look at the sketch and return to me, I thank you very much!

    Sorry for my ignorance, but could you give me a hint of which server in Brazil I could put in place of your HTTP_SERVER to get Date and Time? (Because I believe I can still make your sketch.)

    Once again, thank you very much

    Reply
    1. Machina Post author

      Okay, so the HomeWifi.h header file is being picked up okay. I don’t know what other advice I can give – the code works fine here and it’s clearly working for you in terms of it’s trying to make a wifi connection and is doing what it should when it fails to establish that connection. Have you double- and triple-checked that the SSD and password in the HomeWifi.h file are correct, including use of upper- and lowercase letters?

      Have you tried the exact same Nodemcu board with another script that connects to wifi and that you know works?

      I’m using this code on an Adafruit Huzzah, so it’s possible there are some hardware differences.

      Re the server referred to in HTTP_SERVER, there’s no server you can simply point to. You have to supply a web server on your local network yourself. I’m running a server (actually a Raspberry Pi running Apache) on my local network, hence the 10.0.0.159 IP address. This is running a PHP script that provides the REST API. It’s up to you to write the necessary code to send the room thermometer the required responses when it asks for the time, date and local weather.

      I looked at the PHP code to see if I could share that. But it uses some of my home-made PHP libraries. Plus it pulls data from a text file written by another script, which in turn uses libraries. So the dependencies would be a nightmare. This is why I said that this isn’t code you can simply run as it is.

      Reply
  5. Daniel Fernandes

    I believe this should not be the problem because Adafruit Huzzah and Nodemcu are identical; I’m sorry but …
    I leave you my last request: If you could ever test your code with a Nodemcu esp8266 and give me feedback, I would be grateful. Even so, I’m trying more often.
    Thank you very much for your consideration.

    Reply
    1. Machina Post author

      I don’t think I have a Nodemcu board, although I do tend to collect microcontroller and SBC boards without really knowing what I’ve got. So I’ll look, but I can’t make any promises. 😉

      Reply
  6. Daniel Fernandes

    Hi Machina! Are you all right?
    I just came here to confirm that with esp8266 Nodemcu, it really doesn’t work. Until then, I thought it might be with my PC drivers, but I tested it on another computer, but it doesn’t work either.
    What I find interesting is that the HUZZAH board is identical to the Nodemcu and uses a chip, just the esp8266!
    Hugs from Brazil

    Reply
  7. Daniel Fernandes

    Hi Machina, I dared to write you more this time.
    Because I really liked the design of your project and would like to ask you how to modify the sketch so instead of using iotServer.php to get the time and date, use an ntp server; what do you think?
    PS I do not have enough knowledge to do this.
    Thanks again,
    Daniel

    Reply
    1. Machina Post author

      I’m afraid that’s beyond me, too – that why I used the local server!

      Reply
  8. Daniel Fernandes

    Hi Machina! I am still struggling with your code!
    I have already asked for some help on the arduino forum to use NTP instead of HTTP. Someone left me a basic example of NTP but I couldn’t adapt it to their sketch.

    So I’ve been thinking: I am creating an HTTP_Server, should I request in the html page the same data you requested, ie date and time, to show on the display? Would it be this? Or am I too far away?

    Have you ever done any NTP arduino code using esp8266?
    Thank you++

    Reply
    1. Machina Post author

      The iotServer.php script doesn’t create a page as such. It looks in $_REQUEST to see if there’s a ‘func’ parameter. If so, it looks to see if the value is ‘timereq’ or ‘datereq’ (among others). It then prepares the relevant formatted string which it puts into a variable called $response and then, at the end of the script, it does:
      header(‘content-type: text/plain’);
      header(‘Cache-Control: no-cache, must-revalidate’);
      echo $response;
      Note, this is a plain text output, not HTML. It’s also important that the script does not produce any other output.

      Reply

Leave a Reply to Machina Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.