ESP8266: Weather Station V2 Code published

This is a total make over of the earlier weather station. Instead of building my code
on the NodeMCU lua firmware I decided to switch to the Arduino IDE based development setup.
The reason for this was the constant problems with heap memory running out and other instabilities.
When I finally found code that demonstrated the use of my beloved SSD1306 based OLED 128×64 displays the final piece was in place.

I tried to separate the building blocks of the code into different classes, so they can be reused
easiley for other purposes. There is a class for the SSD1306 display and one for talking to the weather API of forecast.io.

SSD1306

This class interfaces with the display over the I2C bus. Please be aware that I set the bus speed relatively high, in order to have faster refreshes of the display. It can happen that for some reason this value is too high for your setup. Then you’d have to experiment with different values

WeatherClient

I’m using the forecast.io API to retrieve localized weather information. The API returns huge JSON objects which I thought would be hard to handle on the ESP8266. For this reason I wrote a little php script which selects interesting information and transforms it into key=value pairs, separated by a new-line charachter.
This can be handled very memory efficiently on the ESP8266. This step costed some self-convincing, since I’m usually a big fan of well structured data. But you have to think differently on embedded platforms

If you find any bugs or code with room for improvement please let me know. C/C++ is not my mother tongue… The best way to tell me about improvments are pull requests (which is a github feature…).

You find the code here:
https://github.com/squix78/esp8266-projects/tree/master/arduino-ide/weather-station-v2

Update: The WeatherStation Kit!

Order all components needed for the WeatherStation in one Kit. The WeatherStation Kit is available now at the shop: https://shop.squix.ch
Buy the WeatherStation Kit!
Posted by Daniel Eichhorn

Daniel Eichhorn is a software engineer and an enthusiastic maker. He loves working on projects related to the Internet of Things, electronics, and embedded software. He owns two 3D printers: a Creality Ender 3 V2 and an Elegoo Mars 3. In 2018, he co-founded ThingPulse along with Marcel Stör. Together, they develop IoT hardware and distribute it to various locations around the world.

62 comments

  1. I hope I do this right and actually post this comment.
    Excellent work Dani! I really like the carousel idea.
    Am I right thinking that the php code is bein hosted on your system?
    How would I change that to run on my system? I have Apache/PHP on my Raspberry Pi that runs Node Red.

    Good work!

    • Hi Mike. Yes, you are right, the php script is hosted on my system and you can just take it and put it somewhere under your apache root on your RasPi. You might want to adapt the log file path in the script or disable it completely.

      I also added the following rewrite rule in a .htaccess file in the folder where the PHP script is:
      RewriteRule ^([^.?]+)$ %{REQUEST_URI}.php [L]

      This allows you to get a more REST-like url of "/rest/weather" instead of "/rest/weather.php". But your Apache must have mod_rewrite enabled.

      Once you have that, just adapt the path in WeatherClient.cpp to your raspberry pi's URL.

  2. Hope this comment makes it to you, I'm still doing something wrong that's losing my questions/comments. It seems that I can't post comments any better than I can understand this web programing stuff – LOL!

    Anyway – I think I'm just too unfamiliar with web programming methods to make heads or tails of trying to get my local machine to be where the web request goes.
    I don't have a url or name like "mikej.com" – I only have the IP address of my machine. But when I substitute my IP address in the code here –

    client.print(String("GET ") + url + " HTTP/1.1rn" +

    "Host: http://www.squix.orgrn" +
    // try mdj
    // "Host: 192.168.2.177rn" +
    "Connection: closernrn");
    I get a "404" error.
    I think my problem is I'm so far behind as far as learning how this aspect of programming works that I don't even know how to go about troubleshooting – like to see what exactly my local machine is receiving from the ESP, etc etc.

    I think that this old dog trying to learn new programming tricks about GETs and POSTs and JSON and REST and all these other acromyms is just too much for me. Along the way of my learning to program as a profession I just totally skipped the whole web interface area and now when I've tried to find a "web programming for dummies" guide it seems that I can find 10 different "guides" telling me 20 different ways to do what seem to me to be the same thing.

    Anyway – enough rambling and complaining.

    The new version with the carousel display is brilliant! Good job!

    • Do not despair, there is help on the horizon! First of all you need change the IP in client.connect("217.26.50.8", httpPort) line. This establishes the underlying connection to your own server. This is a pure TCP connection, you could use telnet to do the same. Now for your own server you can most probably skip the line with the Host. But this depends on your setup. If you only have one webserver running on your machine I think it is not required.

  3. OK – I gave that a try. Now I get this error on the serial monitor-

    …..
    WiFi connected
    IP address:
    192.168.2.62
    Requesting URL: /weather?apiKey=xxxxmyapikeyhere&lat=39.60&lon=-105.01
    HTTP/1.1 400 Bad Request

    Date: Sun, 14 Jun 2015 23:02:51 GMT

    Server: Apache/2.2.22 (Debian)

    Vary: Accept-Encoding

    Content-Length: 301

    Connection: close

    400 Bad Request

    Bad Request
    Your browser sent a request that this server could not understand.

    Apache/2.2.22 (Debian) Server at 127.0.1.1 Port 80

    closing connection

    I tried making the string with and without the "rest" before the "weather?" but no difference.
    Do I need to do something with the weather.php file? I have it on my server in the /var/www folder but I don't see where it ever gets called in the code.

    I know that the server and php are working – I have a .php file that I can point to that displays my PIR sensors on a floorplan of the house. That works so I'm pretty sure that Apache2 and php are working. If I stop the apache2 service that PIR map thing stops working until I start apache2 again.

  4. Hi Dani

    This looks like a great project and on looking through the code I can understand some of it (bit of a noob)!

    I have eyt to receive my 1.3"OLED but have started by getting the code onto an ESP-01 and just onitoring the serial window. Everything is ok except I have a question on the information coming back from the weather server.

    The questin is over the 2 lines of code in weatherclient.cpp

    } else if (key =="SUMMARY_TODAY") {
    summaryTomorrow = value;

    I have commented out the serial.println(line); to see what coems back and I can indeed see two lines return with the key "SUMMARY_TODAY" however, there are also if else statements looking for the same this same key??. Doesn't it just hit the 1st one each time or am I missing something? The variable name summaryTomorrow suggests the key should be different……

    I hope I have been clear in my question and thanks again for putting this together – great work!

  5. Hi Dani

    This looks like a great project and on looking through the code I can understand some of it (bit of a noob)!

    I have eyt to receive my 1.3"OLED but have started by getting the code onto an ESP-01 and just onitoring the serial window. Everything is ok except I have a question on the information coming back from the weather server.

    The questin is over the 2 lines of code in weatherclient.cpp

    } else if (key =="SUMMARY_TODAY") {
    summaryTomorrow = value;

    I have commented out the serial.println(line); to see what coems back and I can indeed see two lines return with the key "SUMMARY_TODAY" however, there are also if else statements looking for the same this same key??. Doesn't it just hit the 1st one each time or am I missing something? The variable name summaryTomorrow suggests the key should be different……

    I hope I have been clear in my question and thanks again for putting this together – great work!

  6. Hi Dani,

    What a great project you have here. Can you tell me if there is a simple way to run this without the php server on the network?

    Thanks in advance.

    • Hi Pedro
      Yes, there is: use one of the JSON libraries to load the weather data directly from forecast.io. I think it should be possible. If I find the time I'll update the code accordingly… The PHP script just made certain calculations a lot easier…
      Cheers,
      Dani

    • Thank you very much Dani. As soon as my exams get to an end I'll also search about that and if I found somethin usefull I'll post here.

      Cheers

  7. Hello Dani,

    I was working on the project and in the Arduino IDE, I uploaded the code to the Node MCU, but when I downloaded the code, nothing happened. I don't know what I was doing wrong, but I read that you need to install certain drivers to make the screen work as well. I thought I saw code that did that but I wasn't sure. Can you help me with this?

    Thanks, Samuel

    • Hi Samuel
      I guess you'll have to be a bit more specific. What do you see in the console of the Arduino IDE? Is the code transferred succesfully to the NodeMCU? Do which pins did you connect your display? Is it really a I2C display?
      Cheers,
      Dani

    • Hello Dani,

      In the console, it says

      Sketch uses 250,456 bytes (5%) of program storage space. Maximum is 4,194,304 bytes. Uploading 33488 bytes from /var/folders/15/0pmyc0150dq/T/build9097535067003199075.tmp/weather-station-v2.cpp_00000.bin to flash at 0x00000000………………………….
      Uploading 217016 bytes from /var/folders/15/0pmyc0150dq/T/build9097535067003199075.tmp/weather-station-v2.cpp_00000.bin to flash at 0x00010000 ……………………………………………………………………………………………………………………

      I connected the ground to ground, VCC to 3V3, SCL to D6, and SDA to D5. I got the OLED from
      http://www.banggood.com/0_96-Inch-4Pin-White-IIC-I2C-OLED-Display-Module-12864-LED-For-Arduino-p-958196.html
      so I think it is an 12C disply.

      Thanks, Samuel

    • The uploading looks good.
      And your display initialisation is "SSD1306 display(0x3c, 14, 12);"? The project contains all necessary driver for the display. Just to be sure you could try 0x3D or switch the pins: SSD1306 display(0x3C, 12, 14); What do you see when you open Serial Monitor in the Arduino IDE?

    • Hi Dani,

      I tried changing the pins and the 0x3c to 0x3c, but nothing happened again. When I open the serial monitor at 115200 baud it says:
      load 0x40100000, len 28780, room 16
      Is this any help to the situation? Should I order a new/ different OLED?

      Thanks, Samuel

    • I have seen this behavior before. It looks as if the NodeMCU goes into boot mode or any other "unhealthy" mode. Now the question is why. Did you select "NodeMCU V1.0 (ESP-12E" from the board menu, assuming you have a V1.0?

    • It turns out, that, the selected board was NodeMCU (ESP8266 ESP-12 Module).
      Where can I find the code or download to let me download to the Node MCU 1.0?

      Thanks, Samuel

    • Hello Dani,

      I got the Arduino IDE to say NodeMCU 1.0, and now it it kind of working. The screen has the wifi logo on it, with the three dots moving back and forth, but it never connects. In the serial monitor at 115200 baud it says:

      Connecting to
      …………………………………………………………………………………………………………………………………….

      Can you help me with this?
      Thanks, Samuel

    • Hi Samuel
      Have you adapted the ssid and password in the code to your local wifi network? While I plan to use a more elegant connection process this is what you'll have to do now. If you have done this and it is still not connecting, please try it with the different wifi network. The ESP cannot connect to 5Ghz networks and there might also problems with encryption…
      Let me know how this is working for you

      Cheers,
      Dani

  8. Hi Dani,
    I did change the SSID and Password to my network. I tried changing the network, but nothing happened. I don't think my networks are 5Ghz, but I don't know, and I'll look into it. For now it still isn't working.

    Thanks, Samuel

    • My network isn't a 5Ghz network, but it is a WPA2 network, so I was wondering if the encryption is what's causing the problem. Is WPA2 a problem?

      Thanks, Samuel

      Thanks, Samuel

    • Hi Samuel
      It's quite hard to tell from far what might be the issue here. I had some issues with an SSID that contained a dash ("-"). In theory the chip and code supports unprotected, WEP, WPA and WPA2. I have only tested it with WPA2… Maybe the hint with the dash in the ssid helps? Anyway, if you can, I would try to get another access point running (e.g. the Mac can act as one) and than try different names and encryption modes…

      Hope that helps,
      Dani

  9. Hi Samuel,
    What did you do to make display work? I have esp-01 board, same display as yours and when i turn it on display is blank.
    Thank you.

  10. Hi Davor,
    if you use a ESP-01 you do not have pin 14 or 12. Esp-01 uses pin 0 and 2 as I2C bus. You have to change the line
    SSD1306 display(0x3c, 14, 12);
    in the sketch to:
    SSD1306 display(0x3c, 0, 2);
    that will make your sketch run on a esp-01

    Co

  11. I have everything running and I mounted the screen into the box – everything working except the screen is upside down!

    I see there is a function:

    void SSD1306::flipScreenVertically() {

    with a couple of lines of code – I also see some of the same commands appearing in the init function (duplication)?

    Ive tried lots of ways to change the code and it does not seem to make any difference whether the lines of code are present or even commented out? It always comes and boots up upside down….. any ideas?

    • I'm not sure, if I got this right. So you added a line like
      display.flipScreenVertically(); in the setup method and it still doesn't flip? I just tried it with my module and it works just fine…
      The SSD1306 class is a library. You use it weather-station-v2 file to display everything. Did that help you?

    • Thanks for replying Dani – I've managed to get it to work, a the the same time the code is confusing me a bit. I got it flipped the right way by changing the code in the init function from this:

      // sendCommand(0xA0 | 0x1); //SEGREMAP //Rotate screen 180 deg
      sendCommand(0xA0);

      // sendCommand(0xC8); //COMSCANDEC Rotate screen 180 Deg
      sendCommand(0xC0);

      to this:

      sendCommand(0xA0 | 0x1); //SEGREMAP //Rotate screen 180 deg
      //sendCommand(0xA0);

      sendCommand(0xC8); //COMSCANDEC Rotate screen 180 Deg
      // sendCommand(0xC0);

      so, basically swapping the two commands around by commenting and uncommenting the lines.

      However, if the screenis initialised useing this function then why is there another function:

      void SSD1306::flipScreenVertically() {

      This seem to be doubling up?

  12. Hi Samuel

    Can you share the solutions you have found? I'd like to improve post and code with your help!

    Glad that it works now
    Dani

  13. I'm all up and running now which is good. I have noticed something strange though the icon for the tomorrow weather ia a cloud with a moon (same as the today icon – it is 8pm at the moment) – is this correct is the sun not going to rise tomorrow Ha Ha!

    IE: the "Tomorrow" icon is the same as the "Now" icon

  14. Dani,

    I found out your ssd1306_i2c.h library only compiles for the ESP boards.
    The reason is the use of Wire.begin(mySda, mySdc) in the library.
    I suggest you keep that out of the library so that the user can add this line in the setup and select which way he wants to use the library. Either as Wire.begin(mySda, mySdc) for the ESP8266 or as Wire.begin() for the other platforms.
    Some documentation would also be helpfull in using the library.
    Anyway, thanks for your work on this.

    Co.

  15. Dani,

    I found out your ssd1306_i2c.h library only compiles for the ESP boards.
    The reason is the use of Wire.begin(mySda, mySdc) in the library.
    I suggest you keep that out of the library so that the user can add this line in the setup and select which way he wants to use the library. Either as Wire.begin(mySda, mySdc) for the ESP8266 or as Wire.begin() for the other platforms.
    Some documentation would also be helpfull in using the library.
    Anyway, thanks for your work on this.

    Co.

  16. I added a SHT 22 to act as an indoor sensor. (Using a ESP 12). I added a 4th frame to display the results……..

    The code is too long for me to post here unfortunately….I may share it on Instructables if thats ok Dani? With full attribuation of course.

  17. great work you have done till know with the esp8266 and the ssd1306.
    Iam using parts of your code (ssd1306 Lib) for a project.
    I need to display 10 digits with maximum size in one line on the ssd1306.
    Is there a way to change the font or the fontsize? if i use fontscale 2×2 i just get 8 digits in one line.

    Thanks Dominik

    • Hi Dominik
      You could use a different font, but that would require a lot of adaptions, since my code is currently bound a lot to the current font….

  18. Hello Dani!
    Really good project, i got it working after replacing my LCD, seems my first one was faulty. Now I will try to make some nice housing for it. I have one question, is it possible to use wunderground instead of forecast.io? It seems more precise with current conditions and forecast and it has a base of lot personal weather stations all over the world so you can see current temperature of a place near you.

  19. Hi Davor

    Sure, that should not be a problem. I'm actully in the process of replacing the forecast.io and php script. Wunderground is viable option. I'll uptade when I'm done

    Cheers, Dani

  20. Thanks for your answer. Did you try running it without php scrpit? I've seen people fetching data from wunderground with arduino and no problem. I think esp should then be able to do it also.

  21. Hi Dani – I've been trying to get the code working with a 1.3" SH1106 screen. I understand from much searching that the 1106 is similar to the 1306 but with a 132×64 rather than a 128×64. I've tried updating all the references to 128 with 132 but the screen only displays a portion of what it should (and it's scrambled).

    Any chance you could either make the code changeable (between a 1306 and a 1106 driver) or point me in the right direction!

    Cheers
    Simon

    • …well another day over and i managed to work it out….mmmmmmm nice 1.3" display!!!

      I slowed down the function

      void SSD1306::display(void) {

      ….to see what was happening. I see clearly that the display was only writing to page 0. By adding a nested loop around this function and incrementing the page pointer worked!

      Let me know if you want any further details.

    • Would you be willing to post your changes to get the 1.3" / 1106 working? I've been playing with the 128 references. Don't quite understand your fix above. Thanks!

  22. Great job, Dani. I was able to get it to work right away after changing Wire.setClock to 300000, and the pins to 0 and 2. I have been having issues getting wunderground to work ( stack problems) with another project and was pleased to get your code to work flawlessly. Since I live on Northern California, I was trying to find the code to change Celcius to Fahrenheit (C to F). Could you point me to right direction. Wunderground has both Celsius and Fahrenheit.
    Looking forward to your wunderground code, so it does not need to connect to your server.

  23. As a follow-up to my question, I'm not sure if it the problem is with forecast.io. I have the correct longitude and latitude for my area and changed all the "C" to "F" in the code.
    forecast.io is showing 15 degrees cooler than our current temp. It is scorching hot here, around 87 degrees and forecast.io shows 72 degrees when I looked it up in their web site. Another advantage of using wunderground since they have weather stations all over. In fact they have one in my city.

    • Issue resolved. My coordinate was a few degrees off and it's picking up San Francisco weather. I'm about 30 miles away inland from SF.

  24. great work Dani, it worked me well. I was trying to find is it possible to show the current time at the screen. I'm not sure how also to add buttons for sliding instead of the auto sliding. I will keep working on that

  25. Hi Dani,
    Thank You for a great tutorial.I made it using ESP8266-01.Its working with charm.
    Now thinking to write an Instructable on my build.Obviously credit goes to you.
    Keep up the good work

  26. Very nice project; thank you.
    I'm very looking forward to a version without the php.
    Thanks again,
    Cat

  27. great project!
    I can't for the life of me get the display to light up.
    the display works when i run a test from my arduino UNO using adafruit sketch.
    I've changed the D4 and D5 numbers and the board type, ox3c to 0x3D etc.
    Is there a different driver I can try? I bought my both the OLED and nodeMCU on ebay.

    thanks

    paul

  28. Thank you very mutch, very nice project.
    I can confirm the problem with the “display.flipScreenVertically()” function. I’m not able to flip the screen.

  29. My workaround for flipping the Display:
    Copy the content of “flipScreenVertically()” in OLEDDisplay.cpp to sendInitCommands function

  30. Any new ideas on the “• Let’s start with the WiFi Settings. Replace yourssid with the name of your WiFi network and yourpassw0rd with its password. I had problems with a network that contained a dash (“-“)
    in the SSID. If you are having problems consider this hint…”
    All of my SSIDs here are hyphenated, I don’t really want to go buy another router………… Except for a Bosch 1617EVSPK 12 Amp 2-1/4-Horsepower Plunge and Fixed Base Variable Speed Router
    Thanks for everything [else]…

    • Hi Robert

      I fear this is a bug in the WiFiManager library. Have tried hardcoding your settings with WiFi.begin(WIFI_SSID, WIFI_PWD);

      Cheers,
      Dani

  31. Hello squix78

    First of all, nice greetings from St. Margrethen. 🙂

    A great project you have there.
    Only I have a problem, The Skeatch runs so far. It shows with the current time on only I get no weather data displayed N / A
    Do I need to do something special at https://www.wunderground.com?

    LG Dirk

  32. I had to re-generate a new API from wunderground. I had the exact same problem and a new API fixed it.

  33. hi I am a noob at this coding stuff I would like help plzz
    how do I set up the weather station in Arduino ide from the git hub codes

  34. Weather underground made their API for pay now. What can we use instead of WU for getting the weather? Do you have the code for the new one?

Leave a Reply to PedroCancel reply