PlatformIO and JSON woes…

Yesterday was, for the most part, quite a good day for me.  The weather was bad, so it gave me an excuse to stay inside and play, at least for a couple of hours in the morning.  I’m still slowly working away at implementing a simple, forced-air heat distribution system in the house (our only permanent source of heating is a wood-stove in the lounge/kitchen area, so I’ve added some ducting to take hot air from behind the stove and gently and quietly push it out through a vent in the bedroom).  The latest idea is that I’ll have an ESP8266 with a small screen and a DS18B20 (or similar) in the bedroom which will display the temperature and allow manual on/off override of the fan control via a couple of buttons.

Anyway, I’ve had one of those 2.2″ TFT displays sitting around for ages waiting for me to get going, so early yesterday morning I wire-wrapped it to one of the spare “Yellow Development” boards that I have hanging around and then looked around for something to burn into the ESP as a quick test.  I remembered Squix’s weather station and vaguely recalled seeing a TFT version too, so off I went and grabbed it from his GitHub repository.  After a couple of false starts (what is it with Windows and non-case-sensitivity?!?!) it fired up beautifully and (almost) everything sprung into life (be warned, this application uses a lot of flash memory space to store image files, so you might not be able to fit all of the moon phase .bmp files onto your particular ESP).  The display was impressive enough to divert me into going to the Weather Underground site and signing up for a developer’s API ID, just so that I could play with the application a bit more.

So after duly playing around for a while, I noticed from the comments section on Squix’ page that a couple of people had already added some new features, all of which looked interesting, so off I went to GitHub again and cloned Keith Fowler’s latest and greatest version.  This is where the fun started and my free time went down the plughole (and none of the palaver related below is in any way Keith’s fault, I hasten to add).

I’m using PlatformIO as my build environment (it generally works flawlessly and automatically does neat stuff, like shoehorning everything into memory, or finding your FDTI adapter, without having to be told).  When you need libraries you can just do a word search on, say “DS18B20” and then choose the most suitable looking candidate from the list returned.  Keith’s updated version of the application I was trying to install was looking for “simpleDSTadjust.h”, so I duly typed “simpleDSTadjust” into the library search, got one hit and installed that library.  The next run through produced exactly the same error message as previously, “simpleDSTadjust.h not found”.  Having been bitten once earlier in the morning with a case-mismatch between the #include line and the actual file name (just for refererence, “ArialRoundedMTBold_14.h” as opposed to (ArialRoundedMtBold_14.h”), I went back and scanned the #include and file name with a magnifying glass.  Nope, they’re both the same.  Hmmm….

I quickly looked at the library properties files, library.json and library.properties and discovered a minor typo with the repository URL in the .json file.  A quick check with the spec’ showed that this was a required field, so I corrected it and tried again.  Nope, same error.

Ran the platformio “run” (compile) command again, this time with the -v option.  I got a lot more information on the libraries which it had found, but nothing at all on the missing “simpleDSTadjust.h”.   Next, I went to GitHub and found the repository for simpleDSTadjust.  The most recent changes were to the library.json and library.properties files, but the GitHub diff showed only a single character change in both cases; the version number had changed from 1.0.0 to 1.1.0, unlikely to cause such a problem, I thought.

At this point I was beginning to suspect that maybe there was some sort of bug with PlatformIO that perhaps the length and composition of this particular library’s name was triggering.  On a lets-just-try-it-anyway hunch, I updated my platformio.ini file with a line to change the behaviour of the library dependency finder — lib_ldf_mode = deep+.  That didn’t help at all (so much for hunches!).

Next I removed the simpleDSTadjust library from the PlatformIO local cache (.piolibdeps) using the “lib uninstall” command and then downloaded the GitHub version to the local “lib” directory (normally used for your own, locally created libraries which aren’t available in the global, PlatformIO library system), giving it a different, shorter name.  I  updated both the library .cpp and .h files, as well as the #include lines in the TFT application source, to match the new name.  And …exactly the same.  PlatformIO ignored the newly created library and repeated the boring old “not found” error.  This was starting to get a little tiresome.

Working on the assumption now that the problem lay with the library itself and not, after all, with PlatformIO, I went into the library directory and moved all of the files which seemed to be non-essential into a newly created sub-directory.  The next compile actually worked.  It did fall over on some other errors, but we’d got past simpleDSTadjust.h for the time being.  Okay, what was the actual culprit?  Moving the non-essentials back, one by one, then re-running the compile proved the the library.json file was definitely at fault, but staring at it didn’t yield any obvious clues, so back to the on-line manual pages and the examples to see what a good file should look like (I’ve never knowingly created a .json file, so I definitely classify as a bona-fide novice).  It all looked fairly simple …quoted text, colon delimiters between defined name and data and comma delimiters at the end of data lines, except for the last one.  Okay, squint, squint, squint.  Nope nothing obvious.  Back to the examples — curly braces for multi-field data, comma after the closing curly bracket.  More squinting …and finally an answer; that comma delimiter after the closing curly is missing.  I quickly edited the file to include the errant comma and …Yay!  A working compile.  Finally!

Phew!  A couple of hours of precious free time wasted (but only because I was stupid enough to pursue the issue at hand instead of getting on with the actual project) mainly because there was no error message displayed (or perhaps generated) when parsing of the library.json file failed because of a syntax error.  Anyway, the author of the simpleDSTadjust library (Neptune2)updated the library.json file within a few hours of the issue being raised, so a very big thank you to him/her for that.

Now I suppose that I should buckle down and get back to work on that simple temperature display, now that I’ve proved that the hardware works.  🙂

 

‘nuther new something in town …you can safely ignore it!

AI Thinker have obviously been listening …but the question is, to whom.  They’ve just come up with something which they’re calling the “ESP8266 Black board T5” (their capitalization, not mine).  It looks really interesting at first glance.

ESP13/WROOM-02 AI Thinker board, with battery box
AI Thinker “Black board T5” development board with attached battery box

[Update:-  I ended up reworking this board to make it somewhat functional.  If you’re comfortable with a soldering iron, you might be interested in these notes]

There’s a relay and a couple of screw-down connectors at one side of the board and what’s obviously one of the older  (blue) DHT11 temperature/humidity sensors on another side, sitting next to an ESP13/WROOM-02 module.  Between the relay and the DHT11 is a barrel-connector for DC input, but the unit also comes with a 3-cell (AA size) battery box attached via short flying leads (the board itself is just a little bigger than the battery box).  There’s a beeper on the board and there are three LEDs arranged in a vaguely spoke (as in bicycle wheel) shape.  In addition, there are two mini “tact” switches, a couple of jumpers, a slide-type on/off switch and, sitting like a spider in the middle of its web, a mysterious, 32-pin, QFP package chip.  Etched along the edge of the board is “ESP822_IOT_DEMO” (sic) and also “AI-CLOUD INSIDE”.

As usual with the on-line auction site vendors, there’s b’grall useful information on any of the pages which I could find (and as the auction sites advertise it as an “ESP8266 Serial Development Board” it’s also next to impossible to find any useful information on the web, either).  Anyway, just looking at the board I thought it had to be worth the $10 asking price, just in parts alone.  With a bit of luck, the mystery chip might turn out to be an I2C expander or something equally useful.  Throwing caution to the winds (poor old Caution!), I added a single unit (Caution must have crawled back home again while I was surfing dBay) to the next order I made for other odds n’ends.

Tum-de-dum-de-do.  Wait for a couple of weeks.  Odds n’ends arrive, along with da’ board.

AI Thinker
AI Thinker “ESP8266 Black board T5”, with red LED visible just to the left of centre.

Hmmm…  Don’t recognize the number on the top of the mystery chip.  Never mind, throw in some batteries and slide the switch to “On”.  A red LED (which I hadn’t noticed in the pictures) lights up and, after a slight delay, the board starts to emit an annoying “Do something within the next few seconds, or I’ll explode” kinda’ beep.  I press one of the buttons.  It still beeps.  I press the other button.  It still beeps.  I switch it off, hold down one of the buttons and switch it back on.  It starts to beep again.  Same procedure, but other button.  Ahah!  a single beep and then blessed silence …for about a second, then it starts to beep again.  I rip the batteries out and throw the whole thing in a drawer (I was sorely tempted to throw it on the floor and stamp on it, but I thought I might damage the floor).

Back to the web (as there was b’grall documentation in the package, of course) and I resort to a Oogleg image search.  Oogleg’s image processing may be wonderful, but it seems to think that this PCB is a dead-ringer for all sorts of weird and wonderful stuff on the web that just happens to have a black PCB.  I finally find a link to AI Thinker’s forum and a thread which has some links to documents (Yay!), one of which seems to be an English PDF (double Yay!).

My yaying turns out to be a little premature.  The English documentation is limited to the schematic and it’s a fairly useless one, at that.  Many of the components evident on the board aren’t present on the schematic at all, labelling is haphazard, parts are wrongly identified (the 32-pin QFP is labelled as an STC15L2K16S on the schematic, but the part on the board is an STC15L2K32S2 [see below], the sensor is identified as a DH11, but the part on the board is definitely a DHT11) and plugs, sockets and jumper blocks are all depicted as unidentified rectangles.  One thing that does stand out immediately though, is that most of the GPIO pins on the ESP8266 are unconnected.  Uh-oh!

T5 Schematic
Original Schematic

A P-Channel MOSFET (top R/H corner of the schematic) gives another clue to what’s going on here.  The drive signal is labelled “WIFI_VCC”.  It’s a supply-side switch for the ESP8266 power.  The board is battery powered and it looks as though the ESP8266 is only powered up when a network connection is needed (and I recognized this simply because I’m doing the same thing with one of my ESP8266 projects, but using a DS3231 RTC module to drive the power switch).

So, it turns out that AI Thinker have produced a board which has a “master” microcontroller and is using the ESP8266 simply as a network interface.

Next to the on/off slide switch there’s a three-pin connector (barely visible in the photo above – it’s slightly above and to the left of the DHT11) with the silkscreen label “R-G-T”, which appears to be the serial port for the microcontroller (not for the ESP8266).  I pulled the unit out of the drawer again just long enough to connect up the pins and go through the press-beep-disconnect routine a few more times at various baud rates.  I didn’t ever get any indication of any output at all in the terminal window.  Zilch!  Nada!  Nutt’n!  At the same time I fired up a WiFi scan on one of my access points.  I could quite easily see my neighbours’ access points going up and down, but no indication at all that the ESP-13 on the board was ever powered-up.  Back in the drawer wi’thu useless burger!

I might possibly drag the thing out again and have a poke around with a multimeter, but not before I’ve de-soldered that bloody annoying beeper.

The microcontroller chip on the AI Thinker
The microcontroller chip on the AI Thinker “Black board T5”

As far as I can tell from the scant information available for this microcontroller part number available on the web, the chip is an 8051 derivative, with 32K of onboard flash memory.  I haven’t used an 8051 chip in twenty years and, although I’m sure there are some folks out there who will be positively salivating at the thought of an 8051 paired with an ESP8266, there will most certainly be many thousands more who will be scratching their heads and saying “WTF?”.  I’m not (and probably never will be) an AVR/Atmel kinda’ guy, but why AI Thinker would AI Think it a good idea to produce a board for the hobby market with such an odd-ball chip is beyond me.  If they’d dropped in an ATtiny85, a Propeller, an MPS430, a PIC18F/24F, or just about any low-end ARM chip they would have had the (ESP8266) world beating that proverbial path to their door.  As it is, they’re destined to get a big, red “FAIL” stamp splattered across their collective foreheads.  Anyway, if you’re at all interested, I finally found the data sheet for the chip on STC’s web site (no thanks to their total lack of indexing or search function and the quiet inclusion in one data-sheet — with a single processor ID as the only title —  of 18 different chips).  The highlights are, yes 8051 based, 32KB of flash, 2KB of SRAM,  29KB(Eh?!?) of EEPROM, 2 x UART, 3 x PWM, internal clock and 8-channel, 10-bit A-to-D.  If all of that lights your fire, then this is the board for you (and I’ll sell it to you …cheap!).

Hold on just a second; I need to go and add a “Double Duh!” category for this one.

Update – In an effort to introduce some semblance of balance into this post (and especially to note that I’m not, generally “anti” AI-Thinker), I’d like to point you at a couple of articles on one of their other boards, which actually is something of a bargain!  Just about the only thing it has in common with the “T5” is a long and overly complicated name, but you should definitely keep an eye open for the ESP12-based “Yellow Development Board”.  Apart from anything else, it has lots of nice flashing LEDs and you don’t need to resolder anything to get them working.

SDK I2C Code. Today’s “Duh!” Story.

This entry is here as a helper (hopefully) for any other poor soul banging their head against the wall of Espressif’s I2C “master” implementation.  <TL;DR Spoiler>  When using the i2c_master.c code supplied with the IoT SDK, you must call i2c_master_gpio_init() before any other I2C functions in your code (and, obviously, your GPIOs need to be correctly defined beforehand).

ESP8266-03 with DS3231 module and DS18S20
ESP8266-03 with DS3231 module and DS18S20

I’ve been trying for days to get I2C working with an ESP8266-03 and a DS3231 RTC module (the el-cheapo, middle-kingdom one with the AT24C32 memory on the same PCB).  This was starting from scratch with I2C on the ESP8266 for me (I’d previously put together a trio of PICs talking to each other over I2C without too much trouble, so I naively thought that the DS3231 should be a doddle).

Hardware wise, I had the DS3231 hanging off a 4v5 supply and the ESP8266 running from a 3v3 linear regulator, supplied by the same 4v5 source.  The reason for this is that I intend to make the unit into a self-contained, battery-powered data-logger and I want the DS3231 to be able to control the power to the whole shebang through a small MOSFET driven from the alarm output.  The I2C bus is run through a MOSFET-based level shifter to ensure that the ESP8266 pins aren’t over-driven.

As normal, on the software side I started off with TuanPM’s totally excellent MQTT package (and if you’re not using this already, you should be!) as a starting point for my new project.  I simply added the i2c_master.c and i2c_master.h from the Espressif (IoT) SDK into the tree, modified the GPIO settings in i2c_master,h to point to the ESP8266 default I2C pins (GPIO2 for SDA and GPIO14 for SCL), added a tiny calling function into user/user_main.c and compiled.  I flashed the ESP-03 with the RTC module attached and… nothing!.   Okay, quick check… Duh, my SDA and SCL connections on the stripboard were the wrong way round.  Okay, resoldered the jumper wires, double checked with the meter and we’re good to go.  And… nothing.  Again!  My output data resolutely remained at all zeros, but the DS3231 calls (using Richard Burton’s ESP8266-ready code) didn’t throw any errors.  Double duh!

I certainly had no reason to doubt Richard’s code.  He’d only just recently done this himself and has a blog about his ongoing projects that is definitely recommended reading for anyone playing with the ESP8266.  I did have reason to suspect that the hardware might be a touch on the dodgy side though, as the DS3231 module already has a pull-up resistor pack on the I2C lines and the MOSFET level-converter also uses 10k pull-ups to both the 4v5 and 3v3 sides.  Thus the 4v5 side had the DS3231 pull-ups and the level-converter pull-ups in parallel and I suspected that the bus might not be being driven hard enough to a logical “0” on that side because of it.  Back to the soldering station, off with the SMD pull-up pack (and, while I was at it, off with the red-LED and the coin-cell “charging” diode, too…  I don’t need an LED sucking extra current from the 4v5 battery pack and the charge diode, as has been noted in lots of places on the ‘net, is a positive danger when using a normal, non-rechargeable CR2032 in the RTC).  Reconnected and yes, I know you’ve already guessed it, bugroll again.  Sigh!

Back to the soldering station.  Ripped out the original RTC module and slapped in another one.  Bugroll, repeated.

At this point I was considering popping one of the RTCs into a PIC-based board, just to check that I didn’t have two dodgy ones, but on reflection, decided that the quickest and easiest next test was to use another I2C implementation instead.  I had already seen Nathan Chantrell’s ESP8266-enabled OLED project and remembered reading that he’d used Zarya’s I2C implementation to drive the display.  Nathan’s blog is another one of my favourites and he certainly doesn’t seem to get things wrong as often as I do, so off I went to GitHub again and pulled Zarya’s I2C code.  It’s basically just two files, the i2c.c and i2c.h, which replace the i2c_master files from the SDK implementation.  First glitch… that missing word, “master”.  Richard’s code calls the i2c_master_whatever() functions, a couple of which are not compatible, argument wise, with Zarya’s implementation.  Okay, “Cheat” is my middle name, so taking the laziest course of action I just rolled half a dozen, one-line wrappers to encapsulate Zarya’s code into i2c_master_whatever() functions.  The only minor change was to make the ack and nack separate function calls (Zarya’s code sensibly uses a single ack function and passes either a 0 or a 1 depending upon whether it’s actually an ack or a nack).  Flashed and… Hurrah!!  Three cheers!  Two pints of Guinness and a packet of crisps, please!  The module burst into life and sent real data.

Mostly it sent really bad data, but at least not just those boring old zeros any more.  The memory module obviously wasn’t writing data at all and the RTC was returning some really weird values for everything except the seconds value, but the internal temperature sensor in the DS3231 was sending sensible, accurate temperatures (instead of the previous, monotonous “Bit chilly in ‘ere, innit”).  Hmmm, verrry interestink!

Unfortunately though, this still left me in something of a quandry.  Now I knew my hardware was capable of working to some extent, but was the bad data a result of my inept programming of the wrappers, or did I still have a hardware issue of some sort, or (perish the thought) was Zarya’s I2C implementation incompatible with the SDK (which has been updated several times since Zarya originally published his code) or Richards DS3231 driver?  Okay, there are a couple of other I2C implementations out there and one of them, by EADF, implements a replacement i2c_master with a significantly easier method of specifying the GPIO defines than the original, SDK master (EADF is the guy who also brought us “easygpio”, so this should be no surprise).  Off to GitHub again.  “https://github.com/eadf/esp8266_i2c_master”. Download. change out the files. compile, flash and… bugroll again.  Aaaargh!  Now I’m starting to doubt my own sanity.  I trust EADF like a brother.  He’s never let me down where the ESP8266 is concerned.  What’s going on here?

I spent more time looking at the two implementations (Zarya’s and EADF’s) side by side to try and work out what was different and it eventually struck me that there was one extra function in EADF’s code which, while missing from Zarya’s, was also present in the SDK version —  i2c_master_gpio_init(). So I finally check the much maligned and utterly useless SDK documentation and, yes, there it is, labelled as “Function: set GPIO in i2c master mode“, nothing else.  Looking at the code itself, it’s obvious that the function does pretty much nothing, other than the all-important job of setting the GPIO pins to the correct mode for I2C (and Espressif have even helpfully commented their code with “//open drain” on those lines), before calling the I2C initialize function.  So, the documentation, despite it’s shortcomings, isn’t so utterly useless after all (just bloody useless!) and a quick edit of my calling code to replace i2c_master_init() with i2c_master_gpio_init() caused it all to spring back into life again… this time with sensible data coming from the RTC and the AT24C32 memory chip, too.  Yip-finally-ee!

Bottom line (same as the top one)…  When using the i2c_master.c code supplied with the IoT SDK, you must call i2c_master_gpio_init() before any other I2C functions in your code (and, obviously, your GPIOs need to be correctly defined beforehand).  Failure to do so will cause hours of frustration (this seems to be my standard state when trying to do almost anything with the ESP8266 nowadays) and will also cause your significant other (and possibly the neighbours) to complain about the unrestrained use of Anglo-Saxon and unwarranted cat kicking.