Category Archives: LCD

The LCD Object

lcdIt has been a very busy week for us here in Spain – what with partying and what-not, so I’ve not had as much time as I would like to develop my JavaScript object skills, however, I’ve managed to get much further with a project I’ve been working on in the background – a little LCD display.

I wanted to simulate a real LCD and you’ll have seen in an earlier blog entry that I managed some JavaScript code to do this.  Well, I’ve had all SORTS of unexpected issues, now resolved and I’ll detail here what I’ve done.

colour changeSo first off, I was having some interaction with other objects on the page – resolved – but an issue that came to light when I got here to Spain – with my little Raspberry Pi that is running this stuff left in England – was that of loading external items – for example, images and fonts.  Designing items for Node-Red Dashboard is slightly different to working on an empty web page as you’re basically working inside a DIV – you don’t have the luxury of ONLOAD and HEADERS etc. and I found myself getting annoyed with my web seven-segment font not working when first loaded  - i.e. initial text would show up in a default font because of the time it takes to load the web font from England. I could not understand why this would always happen – surely there’s some caching going on? But if you read the comments in previous blogs – that apparently is not the case as the templates in Node-Red Desktop add a timestamp to URL calls which kills the cache. Well, not ALL of it but certainly makes life difficult when trying to load up fonts and images. 

LCD in redAnyway, the first idea that came out of various comments was to URL encode the fonts – and of course, wanting to keep with good practice I put all of that into a separate style sheet. NO! The page has to load the style sheet, so the problem doesn’t go away. The answer lay in having the font inline – now that SOUNDS messy but actually it’s not that big a deal especially if you don’t have wrapping turned on – it’s just a one liner – albeit a very long line. The breakthrough came when I read a suggested link which took me to Fontsquirrel – having initially used this 14-segment font for my LCD only to find that the capital S was a bit naff and the spacing was NOT identical on all characters, I was then quite excited when I found an excellent WOFF file called segment14 here.  Mono spaced and with a decent S.

Lovely, but of course this still had the same issue with loading – not a big issue at home but as soon as myself and the source were separated by a plane trip – the loading issue became apparent. Anyway, Joe Lippa and Antonio (Mr Shark) have been feeding me links and it turns out that FontSquirrel can load up the font and return a CSS file with the code all inline (they don’t appear to have 7 or 14 segment fonts so it is as well you can upload fonts you have found -  and have them converted) – so no external loading.  In the data that came back was a WOFF data block and a WOFF2 data block – I ditched the former as the latter works just fine.  I’ve put links to fonts here – I’ve modified them for my own use but you should know I’m not claiming any ownership of the fonts – others have done the excellent work on designing the fonts.

Purple LCDWith the font issue resolved I set about making a basic object for a display (which will no doubt mutate – but right now can be dropped into a template in Node-Red to show lines of simulated 7-segment display in a variety of colours. Methods can be invoked to updated the two lines and to change the colours – both background and foreground. I managed my colours by trial and error but you can of course change them and add more.

Simple testing of the LCD objectThis, then, is merely the first stage – everything works – you can change colours and text… so much more can be done – choice of how many lines, how many characters, what font size etc. but all of that is easy to add once the basic idea is in place. This is going to be added to my armoury of gauges and shapes available in Node-Red Dashboard – I’m playing with the GITHUB beta right now and it is coming along VERY nicely – now that the actual template width and height can be tweaked.

Anyway, there it is… if you want to play with this – grab the code and paste into a template via the “import clipboard” option (top right – 3 bars)– yes, it’s big because of the font – but very do-able. You can replicate this and make two or more displays but more likely the object and font should be split off into another template if you plan to do that. 


Note that in my test inject nodes I am now injecting JSON, not text (see image above and note the {} which means JSON is selected – then I’ve filled in some standard JSON text to adjust two variables) – just as easy but more powerful as you’ll see in the text injectors.

When this information comes into the node it is processed as such…

        scope.$watch('msg', function(msg) {
            if ((msg.payload.lcdm1!==undefined)&&(msg.payload.lcdm1!==undefined)) lcd2.update(msg.payload.lcdm1,msg.payload.lcdm2);
            if (msg.payload.colour!==undefined) lcd2.updateCol(msg.payload.colour);

Right now I don’t allow on or the other line to be processed but only both at once – but that would be easy to change.

If you look into the code there are two methods (functions) of relevance once the object is defined – this.update and this.updateCol – which are merely setting internal variables then calling the update function.  The text update function could easily be split into two.

At the very end, the LCD is created, needing only a DIV to work in..

var lcd2 = new myLcd("newDiv1");

I called it lcd2 as I also tried putting several on a page to ensure there was no interaction. They need unique names and unique div names and several will co-exist no problem (though it would make sense to have only one copy of the object definition if you want to do the job properly).

See previous blog entries for related info on LCD simulation (alpha blending of the all-segments on character under the actual text).

Specific questions are invited in the comments area (not 2 years later please).


Another LCD

LCD colours by Peter ScargillWhen writing that last blog entry about an LCD with time and date display and programmable temperature for Node-Red Dashboard, it occurred to me that it would be worthwhile making a simple one-liner (6*1) LCD with a 20-character display. At the same time I wanted to simplify it right down and here’s the result. Should make a good starting point for anyone wanting to develop their own.


In this case you simply fire a message at the template node. You only need one font for this from the ones used in the previous entry (really you should read the previous article to understand how to load the fonts in – trivial).

I’ve done a check on msg.payload and if the first character is a period I then use the remainder of the message to select colour – hence…


And that really is it – really simple to use – make the template 6*1,insert the code, make sure the font is in place and when you run it – you can select the sample text or play with the colours – enjoy.

LCD colours by Peter Scargill

LCD colours by Peter Scargill

LCD colours by Peter Scargill

[{"id":"7744e0e4.38986","type":"inject","z":"c552e8d2.712b48","name":"","topic":"","payload":"Hello there","payloadType":"str","repeat":"","crontab":"","once":false,"x":800,"y":1180,"wires":[["864d97a5.30d348"]]},{"id":"543d4cba.38a7a4","type":"inject","z":"c552e8d2.712b48","name":"green","topic":"","payload":".blackOnGreen","payloadType":"str","repeat":"","crontab":"","once":false,"x":790,"y":1220,"wires":[["864d97a5.30d348"]]},{"id":"658a2f15.d95bc","type":"inject","z":"c552e8d2.712b48","name":"orange","topic":"","payload":".blackOnOrange","payloadType":"str","repeat":"","crontab":"","once":false,"x":790,"y":1260,"wires":[["864d97a5.30d348"]]},{"id":"b60e3a3f.931078","type":"inject","z":"c552e8d2.712b48","name":"blue","topic":"","payload":".blackOnBlue","payloadType":"str","repeat":"","crontab":"","once":false,"x":790,"y":1300,"wires":[["864d97a5.30d348"]]},{"id":"62767df.a99d984","type":"inject","z":"c552e8d2.712b48","name":"yellow","topic":"","payload":".blackOnYellow","payloadType":"str","repeat":"","crontab":"","once":false,"x":790,"y":1340,"wires":[["864d97a5.30d348"]]},{"id":"ad983ec0.bd2ed","type":"inject","z":"c552e8d2.712b48","name":"white","topic":"","payload":".blackOnWhite","payloadType":"str","repeat":"","crontab":"","once":false,"x":790,"y":1380,"wires":[["864d97a5.30d348"]]},{"id":"a046dc0e.953ea","type":"inject","z":"c552e8d2.712b48","name":"pink","topic":"","payload":".blackOnPink","payloadType":"str","repeat":"","crontab":"","once":false,"x":790,"y":1420,"wires":[["864d97a5.30d348"]]},{"id":"8372ff69.e0a4c","type":"inject","z":"c552e8d2.712b48","name":"red and light text","topic":"","payload":".yellowOnRed","payloadType":"str","repeat":"","crontab":"","once":false,"x":820,"y":1460,"wires":[["864d97a5.30d348"]]},{"id":"5fcd3b1d.a64954","type":"inject","z":"c552e8d2.712b48","name":"cyan and white","topic":"","payload":".whiteOnCyan","payloadType":"str","repeat":"","crontab":"","once":false,"x":820,"y":1500,"wires":[["864d97a5.30d348"]]},{"id":"a81aab9f.8f78a8","type":"inject","z":"c552e8d2.712b48","name":"lime on black","topic":"","payload":".limeOnBlack","payloadType":"str","repeat":"","crontab":"","once":false,"x":810,"y":1540,"wires":[["864d97a5.30d348"]]},{"id":"864d97a5.30d348","type":"ui_template","z":"c552e8d2.712b48","group":"33279d5b.72b122","name":"LCD","order":0,"width":"6","height":"1","format":"<script>\n    var LCDColours={\n    \"blackOnOrange\": {items:[\"#222\",\"#fb7c00\"]},    \n    \"blackOnGreen\" : {items:[\"#222\",\"#66ac66\"]},\n    \"blackOnBlue\" : {items:[\"#222\",\"#8888ff\"]},\n    \"blackOnYellow\" : {items:[\"#222\",\"#bbbb44\"]},\n    \"blackOnWhite\" : {items:[\"#222\",\"#aaaaaa\"]},\n    \"blackOnPink\" : {items:[\"#222\",\"#ff8888\"]},\n    \"yellowOnRed\" : {items:[\"#ccaa22\",\"#aa2222\"]},\n    \"whiteOnCyan\" : {items:[\"#dddddd\",\"#227777\"]},\n    \"orangeOnBlack\" : {items:[\"#ff8800\",\"#000000\"]},  \n    \"limeOnBlack\" : {items:[\"#00cc55\",\"#000000\"]} \n    } ;\n\n   (function(scope){ \n            scope.$watch('msg', function(msg) {\n                if (typeof(msg.payload) != \"undefined\") \n                        {\n                            if (msg.payload.substring(0,1)!=\".\") $(\"#LCDTextBody\").text(msg.payload);  \n                            else\n                            {\n                              msg.payload=msg.payload.substring(1);\n                              $(\".LCDWrapper\").css('background-color', LCDColours[msg.payload].items[1]);  $(\".LCDTextFront\").css('color', LCDColours[msg.payload].items[0]); \n                              if (LCDColours[msg.payload].items[1]==\"#000000\") $(\".LCDTextBack\").css('color',\"rgba(255,255,255,0.15)\"); else  $(\".LCDTextBack\").css('color',\"rgba(0,0,0,0.1)\");                                \n                                \n                            }\n                        }   \n            });\n    })(scope);\n\n</script>\n\n<style type=\"text/css\">\n@font-face {\n  font-family: \"D14MI\";\n  src: url(\"/myfonts/DSEG14Modern-Italic.woff\") format('woff');\n}\n\n\n.LCDWrapper{\n\tposition:relative;\n\tborder:3px solid #000;\n\tborder-radius:8px;\n\theight:66px;\n\twidth:304px;\n\tcolor: 0;\n    font-family: \"D14MI\";\n\tbackground-color:#66ac66;\n\tbox-shadow: 3px 3px 10px 0px rgba(0,0,0,0.3) inset; \n}\n\n.LCDTextBack{\n\tz-index:50; color:rgba(0,0,0,0.1); \n}\n\n.LCDTextFront{\n\tz-index:51; color:rgba(0,0,0,1);\n}\n\n.LCDTextBack,.LCDTextFront {\n   \tposition:absolute;\n\ttop:3px;\n\tleft:6px; \n\tfont-size:18px;\n}\n\n</style>\n\n<div class=\"LCDWrapper\">\n\t<span class=\"LCDTextBack\">~~~~~~~~~~~~~~~~~~~~</span>\n\t<span class=\"LCDTextFront\" id=\"LCDTextBody\" ></span>\n\n</div>\n","storeOutMessages":false,"fwdInMessages":false,"x":990,"y":1320,"wires":[[]]},{"id":"8e623ee.81f9bc","type":"inject","z":"c552e8d2.712b48","name":"","topic":"","payload":"Goodbye","payloadType":"str","repeat":"","crontab":"","once":false,"x":800,"y":1140,"wires":[["864d97a5.30d348"]]},{"id":"33279d5b.72b122","type":"ui_group","z":"","name":"LCD Test","tab":"34cddaf3.8a9cd6","disp":true,"width":"6"},{"id":"34cddaf3.8a9cd6","type":"ui_tab","z":"","name":"testz","icon":"dashboard"}]

LCD Display for Node-Red

Pete's LCDAs must be obvious by now, I’m on a roll here. Having decided that Node-Red Dashboard is the way forward ( would in the past have used BLYNK or Imperihome) I’ve been getting to grips with the dashboard and as you’ll see if you check recent blogs I’ve had a fair bit of success with various CANVAS based libraries, getting them into the Dashboard.

Pete's LCDAnd so it was that over the weekend, MrShark contacted me with this link – a very nice, simple stand-along clock display. Well, that fired me up and so I grabbed the code and started ripping it apart.  One thing led to another and here we have a nice LCD display programmable in a wide range of (I have to say stunning) colours and able to display temperature or weather icons on the right  – and in the process I learned a few things such as what position-absolute is all about and a great deal about transparency.

Pete's LCDIn the display here you see the use of border shadows, 7-segment display fonts and transparency to give the impression of an old-fashioned LCD display – I think it does a nice job.  The code here displays the time, date and day automatically and you can inject temperature into it – but a brief look and you’ll soon realise that you could put just about anything in there – so I look forward to feedback from readers.  To make this work, from the link above I had to grab 3 fonts (DSEG7Modern-Italic.woff,  DSEG14Modern-Italic.woff and DSEG7Modern-BoldItalic.woff – also required is  DSEGWeather.woff) from the link above (into myfonts – see previous blogs for the reason I made up directory names like myfonts and mycss etc).

Pete's LCDSo – here is the code to put into a Dashboard template – you just need to inject msg.payload to set the temperature OR weather icons depending on mode – see flow – most of this is just for you to experiment with.

tmp484EThere are several spans in here – all position absolute – which means they overlap and are all relative to the top left of the main DIV – the trick with the LCD is simply the 8 figure semi-transparent – with you number or letter sitting on top of it. Works a treat I should say.  You’ll want a 6*2 size for the template… but of course you may choose to resize this completely.


tmpF88BAn important item include the z-index, I’ve used 50 and 51 arbitrarily – the original code this all came from used 100 and that ended up over-writing the Node-Red Dashboard menu! Of course if you don’t want to show temperature you could make that humidity or anything else really.

tmpA42CInjecting weather – see flow – includes: characters “0” to “9” for; background all segments, sun, cloud, rain, hard rain, snow, thunder rain, thunder hard rain, thunder, sun and cloud and finally “:” for all off.

Below is the code for the flow - make sure you have those fonts and inject this lot into a page in the dashboard - you'll need to change the tab details to suit yourself.

Oh, this page I found while looking for colour ideas…

[{"id":"5439cd84.a88ae4","type":"ui_template","z":"c552e8d2.712b48","group":"1e03a2b2.83a61d","name":"Time and Temp","order":0,"width":"6","height":"2","format":"<script>\n    var icon=\"T\";\n\n        \n    var colours={\n    \"blackOnOrange\": {items:[\"#222\",\"#fb7c00\"]},    \n    \"blackOnGreen\" : {items:[\"#222\",\"#66ac66\"]},\n    \"blackOnBlue\" : {items:[\"#222\",\"#8888ff\"]},\n    \"blackOnYellow\" : {items:[\"#222\",\"#bbbb44\"]},\n    \"blackOnWhite\" : {items:[\"#222\",\"#aaaaaa\"]},\n    \"blackOnPink\" : {items:[\"#222\",\"#ff8888\"]},\n    \"yellowOnRed\" : {items:[\"#ccaa22\",\"#aa2222\"]},\n    \"whiteOnCyan\" : {items:[\"#dddddd\",\"#227777\"]},\n    \"orangeOnBlack\" : {items:[\"#ff8800\",\"#000000\"]},  \n    \"limeOnBlack\" : {items:[\"#00cc55\",\"#000000\"]},  \n    }  \n    \n    var daylist = [\"sun\", \"mon\", \"tue\", \"wed\", \"thu\", \"fri\", \"sat\"];\n    (function(scope){ \n            scope.$watch('msg', function(msg) {\n               if (typeof(msg.type) != \"undefined\") icon=msg.type;\n    \n               if (icon==\"t\")\n                    {\n                        $(\"#DSEGWEATHER-BACK\").text(\" \");\n                        $(\"#DSEGWEATHER-ICON\").text(\" \");\n                        $(\"#DSEGTempcF\").text(\"C\");\n                        $(\"#DSEGTempcB\").text(\"8\");                        \n                        if (typeof(msg.payload) != \"undefined\") { $(\"#DSEGTempF\").text(msg.payload);  $(\"#DSEGTempB\").text(\"88\"); }\n                    }\n                else\n                    {\n                        $(\"#DSEGTempF\").text(\"\");\n                        $(\"#DSEGTempcF\").text(\"\");\n                        $(\"#DSEGTempB\").text(\"\");\n                        $(\"#DSEGTempcB\").text(\"\");\n                        $(\"#DSEGWEATHER-BACK\").text(\"0\");\n                        if (typeof(msg.payload) != \"undefined\") $(\"#DSEGWEATHER-ICON\").text(msg.payload);\n                        \n                    }\n               if (typeof(msg.colour) != \"undefined\") {\n                              $(\".Clock-Wrapper\").css('background-color', colours[msg.colour].items[1]);  $(\".lcdClock\").css('color', colours[msg.colour].items[0]); \n                              if (colours[msg.colour].items[1]==\"#000000\") $(\".background\").css('color',\"rgba(255,255,255,0.15)\"); else  $(\".background\").css('color',\"rgba(0,0,0,0.1)\");\n                        }\n            });\n    })(scope);\n\n    function genTimerStrings(tm, num){\n    \n    \tvar i;\n    \tvar ret = tm.toString(10);\n    \tvar left = ret.length;\n    \n    \tif( left < num){\n    \t\tfor(i=0; i<( num - left ); i++ ){\n    \t\t\tret = String(0) + ret;\n    \t\t}\n    \t}\n    \treturn ret;\n    }\n\n    function updateTimer(){\n    \tvar ret;\n    \tvar date = new Date();\n    \tvar tm_year, tm_mon, tm_date, tm_hour, tm_min, tm_sec, tm_msec,tm_day;\n    \tvar colon;\n    \ttm_year = date.getFullYear();\n    \ttm_mon = date.getMonth()+1;\n    \ttm_date = date.getDate();\n    \ttm_day = date.getDay();\n    \ttm_hour = date.getHours();\n    \ttm_min = date.getMinutes();\n    \ttm_sec = date.getSeconds();\n    \ttm_msec = date.getMilliseconds();\n    \n    \ttm_mon = genTimerStrings(tm_mon, 2);\n    \ttm_date = genTimerStrings(tm_date, 2);\n    \ttm_hour = genTimerStrings(tm_hour, 2);\n    \ttm_min = genTimerStrings(tm_min, 2);\n    \ttm_sec = genTimerStrings(tm_sec, 2);\n    \ttm_day = daylist[tm_day];\n    \n    \tif( tm_msec > 499 ){\n    \t\tcolon = ' ';\n    \t}else{\n    \t\tcolon = ':';\n    \t}\n    \n    \tdocument.getElementById(\"DSEGClock\").innerHTML = tm_hour + colon + tm_min + \"<span style=\\\"font-size:30px;\\\">\"  + tm_sec + \"</span>\";\n    \tdocument.getElementById(\"DSEGClock-Year\").innerHTML = \"<span class=\\\"D7MI\\\">\" + tm_year + \"-\" + tm_mon + \"-\" + tm_date + ' ' + \"</span><span class=\\\"D14MI\\\">\" + tm_day  +  \".\" + \"</span>\";\n    \n    \tsetTimeout(\"updateTimer()\", 500 - date.getMilliseconds()%500 );\n    }\n\n    updateTimer();\n    \n</script>\n\n<style type=\"text/css\">\n.lcdClock {\n\tbackground-color:#fbfbfb;\n\tfont-size:100%;\n\tpadding-left:10px;\n\tpadding-right:10px;\n\tpadding-bottom:10px;\n\tmax-width:300px;\n\tline-height:160%;\n\tcolor:#222;\n\tfont-family:Meiryo, 'Lucida Grande','Hiragino Kaku Gothic ProN', sans-serif;\n}\n\n@font-face {\n  font-family: \"D7MI\";\n  src: url(\"/myfonts/DSEG7Modern-Italic.woff\") format('woff');\n}\n\n@font-face {\n  font-family: \"D14MI\";\n  src: url(\"/myfonts/DSEG14Modern-Italic.woff\") format('woff');\n}\n\n@font-face {\n  font-family: \"D7MBI\";\n  src: url(\"/myfonts/DSEG7Modern-BoldItalic.woff\") format('woff');\n}\n\n@font-face {\n  font-family: \"DWEATHER\";\n  src: url(\"/myfonts/DSEGWeather.woff\") format('woff');\n}\n\n.Weather-Background{\n\tz-index:50;\n\tposition:absolute;\n\ttop:24px;\n\tleft:226px;\n\tfont-size:68px;\n}\n\n.Weather-Front{\n\tz-index:51;\n\tposition:absolute;\n\ttop:24px;\n\tleft:226px;\n\tfont-size:68px;\n}\n\n.D7MI {\nfont-family: \"D7MI\";\n}\n\n.D7MBI {\nfont-family: \"D7MBI\";\n}\n\n.D14MI {\nfont-family: \"D14MI\";\n}\n\n.DWEATHER {\nfont-family: \"DWEATHER\";\nfont-size:68px;\nheight:68px;\n}\n\n.Clock-Wrapper{\n\tposition:relative;\n\tborder:6px solid #000;\n\tborder-radius:9px;\n\theight:68px;\n\twidth:280px;\n\tbackground-color:#fb7c00;\n\tbackground-color:#66ac66;\n\tbox-shadow: 4px 4px 28px 0px rgba(0,0,0,0.3) inset; \n}\n\n.Clock-Time-Background{\n\tz-index:50;\n}\n\n.Clock-Time-Front{\n\tz-index:51;\n}\n\n.Clock-Time-Background,.Clock-Time-Front {\n   \tposition:absolute;\n\ttop:38px;\n\tleft:5px; \n\tfont-size:42px;\n}\n\n.background { color:rgba(0,0,0,0.1); }\n\n.Clock-Year-Background{\n\tz-index:50;\n\tfont-size:18px;\n}\n\n.Clock-Year-Front{\n\tz-index:51;\n}\n\n.Clock-Year-Background,.Clock-Year-Front {\n   \tposition:absolute;\n\ttop:2px;\n\tleft:5px; \n\tfont-size:18px;\n}\n\n.temp { z-index:51; }\n.tempBack { z-index:50; color:rgba(0,0,0,0.1); }\n.temp,.tempBack {\n   \tposition:absolute;\n\ttop:28px;\n\tleft:210px; \n\tfont-size:42px;\n}\n\n.tempc { z-index:51; }\n.tempcBack { z-index:50;  }\n.tempc,.tempcBack {\n   \tposition:absolute;\n\ttop:36px;\n\tleft:278px; \n\tfont-size:24px;\n}\n\n#DSEG7_OUTPUT{\n\tfont-family: \"D7MI\";\n}\n\n#DSEG14_OUTPUT{\n\tfont-family: \"D14MI\";\n}\n\n#DSEG14_OUTPUT, #DSEG7_OUTPUT{\n\tfont-size:18px;\n\tmargin-top:2px;\n\tmargin-bottom:10px;\n}\n\n</style>\n\n\n<div class=\"Clock-Wrapper center lcdClock\">\n\t<span class=\"Clock-Time-Background background  D7MBI\">88:88<span style=\"font-size:30px;\">88</span></span>\n\t<span id=\"DSEGClock\" class=\"Clock-Time-Front D7MBI\"></span>\n\t<span class=\"Clock-Year-Background background\"><span class=\"D7MI\">2088-88-88</span><span class=\"D14MI\"> ~~~</span></span>\n\t<span id=\"DSEGClock-Year\" class=\"Clock-Year-Front\"></span>\n\t\n\t<span id=\"DSEGTempF\" class=\"temp D7MBI\">00</span>\n\t<span id=\"DSEGTempB\" class=\"tempBack background D7MBI\">88</span>\t\n\t<span id=\"DSEGTempcF\" class=\"tempc D7MI\">C</span>\n\t<span id=\"DSEGTempcB\" class=\"tempcBack background D7MI\">8</span>\n\t\n\t\n\t<span id=\"DSEGWEATHER-BACK\" class=\"Weather-Background background DWEATHER\"></span>\n\t<span id=\"DSEGWEATHER-ICON\" class=\"Weather-Front DWEATHER\"></span>\n\t\t\n</div>\n\n","storeOutMessages":true,"fwdInMessages":false,"x":480,"y":1480,"wires":[[]]},{"id":"e26a920b.fd916","type":"inject","z":"c552e8d2.712b48","name":"21c","topic":"","payload":"21","payloadType":"num","repeat":"","crontab":"","once":false,"x":90,"y":1220,"wires":[["5439cd84.a88ae4"]]},{"id":"a92b9b7a.795228","type":"inject","z":"c552e8d2.712b48","name":"32c","topic":"","payload":"32","payloadType":"num","repeat":"","crontab":"","once":false,"x":90,"y":1260,"wires":[["5439cd84.a88ae4"]]},{"id":"6d378317.dd743c","type":"inject","z":"c552e8d2.712b48","name":"green","topic":"","payload":"blackOnGreen","payloadType":"str","repeat":"","crontab":"","once":false,"x":90,"y":1400,"wires":[["a23865de.5f59b8"]]},{"id":"24a314bf.90927c","type":"inject","z":"c552e8d2.712b48","name":"orange","topic":"","payload":"blackOnOrange","payloadType":"str","repeat":"","crontab":"","once":false,"x":90,"y":1440,"wires":[["a23865de.5f59b8"]]},{"id":"a23865de.5f59b8","type":"function","z":"c552e8d2.712b48","name":"","func":"msg.colour=msg.payload;\nmsg.payload=undefined;\nreturn msg;","outputs":1,"noerr":0,"x":270,"y":1480,"wires":[["5439cd84.a88ae4"]]},{"id":"c8edfc9b.be6ce","type":"inject","z":"c552e8d2.712b48","name":"blue","topic":"","payload":"blackOnBlue","payloadType":"str","repeat":"","crontab":"","once":false,"x":90,"y":1480,"wires":[["a23865de.5f59b8"]]},{"id":"18a1c3a.b9c283c","type":"inject","z":"c552e8d2.712b48","name":"yellow","topic":"","payload":"blackOnYellow","payloadType":"str","repeat":"","crontab":"","once":false,"x":90,"y":1520,"wires":[["a23865de.5f59b8"]]},{"id":"a5c4dd24.4b6ff","type":"inject","z":"c552e8d2.712b48","name":"white","topic":"","payload":"blackOnWhite","payloadType":"str","repeat":"","crontab":"","once":false,"x":90,"y":1560,"wires":[["a23865de.5f59b8"]]},{"id":"83e6ddc0.ec7bd","type":"inject","z":"c552e8d2.712b48","name":"pink","topic":"","payload":"blackOnPink","payloadType":"str","repeat":"","crontab":"","once":false,"x":90,"y":1600,"wires":[["a23865de.5f59b8"]]},{"id":"ebfd33d8.c8b13","type":"inject","z":"c552e8d2.712b48","name":"red and light text","topic":"","payload":"yellowOnRed","payloadType":"str","repeat":"","crontab":"","once":false,"x":120,"y":1640,"wires":[["a23865de.5f59b8"]]},{"id":"26972f6.8af94d","type":"inject","z":"c552e8d2.712b48","name":"cyan and white","topic":"","payload":"whiteOnCyan","payloadType":"str","repeat":"","crontab":"","once":false,"x":120,"y":1680,"wires":[["a23865de.5f59b8"]]},{"id":"10449ff5.d9588","type":"inject","z":"c552e8d2.712b48","name":"Type t for TEXT","topic":"","payload":"t","payloadType":"str","repeat":"","crontab":"","once":false,"x":120,"y":1760,"wires":[["fe927255.d2e2a"]]},{"id":"3e44785a.6181b8","type":"inject","z":"c552e8d2.712b48","name":"Type w for weather","topic":"","payload":"w","payloadType":"str","repeat":"","crontab":"","once":false,"x":130,"y":1800,"wires":[["fe927255.d2e2a"]]},{"id":"fe927255.d2e2a","type":"function","z":"c552e8d2.712b48","name":"","func":"msg.type=msg.payload;\nmsg.payload=undefined;\nreturn msg;","outputs":1,"noerr":0,"x":310,"y":1740,"wires":[["5439cd84.a88ae4"]]},{"id":"94706c5b.a9292","type":"inject","z":"c552e8d2.712b48","name":"weather 2","topic":"","payload":"2","payloadType":"str","repeat":"","crontab":"","once":false,"x":100,"y":1299,"wires":[["5439cd84.a88ae4"]]},{"id":"77b95bb8.1ce774","type":"inject","z":"c552e8d2.712b48","name":"weather 3","topic":"","payload":"3","payloadType":"str","repeat":"","crontab":"","once":false,"x":100,"y":1339,"wires":[["5439cd84.a88ae4"]]},{"id":"30c75186.ef732e","type":"inject","z":"c552e8d2.712b48","name":"lime on black","topic":"","payload":"limeOnBlack","payloadType":"str","repeat":"","crontab":"","once":false,"x":110,"y":1720,"wires":[["a23865de.5f59b8"]]},{"id":"1e03a2b2.83a61d","type":"ui_group","z":"","name":"testy","tab":"f9bab960.c839b8","disp":true,"width":"6"},{"id":"f9bab960.c839b8","type":"ui_tab","z":"","name":"testy","icon":"dashboard"}]

I2C Continuum

Updated August 07. 2016: This article which started off discussing the “new addition” of i2c to the home control software, is now NOT ONLY about an I2c  2/4 line LCD display facility recently added to the ESP8266 boards – but there’s a PARALLEL version as well, making use of GPIO 4,5,12,13,15 and 16. And NOW – I’m adding a pretty crude interface for the Seeeed OLED displays with other OLEDs to follow.

Comments below about format apply equally to the I2c and parallel versions – for the latter, simply use device 255. Note when you do that you lose GPIO13 as an indicator automatically until next power-up.

Success with I2c – once I realised there was something up at the Arduino end which I could work around, my ESP8266 I2c endeavours have been coming on in leaps and bounds!

And here is my test rig – or one of them – I have one for I2c display and another for parallel display  - the latter is just as messy and has more wires:


So what you’re looking at there from top to bottom – is a prototyping ESP8266 board (the author will recognise it) just because I had it handy – ESP-12 based, running my rapidly developing software (which now has loads of spare RAM thanks to the SDK 2.0). I put a simple set of i2c commands in there then promptly realised that a series of commands sent by MQTT would not be a lot of use. I then proceeded to waste the day, having already talked successfully to an 8-bit port expander, trying to get one of those back-of-an-LCD I2C boards to work – as it was based on the same chip.

Parallel versionAfter several hours of considering taking up brick-laying I realised the damned thing was bust – and went off in search of my  cheap Chinese port expander – that’s the red thing you see in the middle. The only difference is this does not have a transistor to power an LCD backlight so I just hardwired that. At the bottom – the original test 4-line LCD. Over on the right, an irrelevant Arduino-type board which is also talking I2c successfully.

Having decided I liked the idea of plugging one of the cheap LCDs onto the odd home control board for information purposes, I set about doing something I’ve never done before – reading the Hitachi data sheet. These things are quite cute once you get over starting in 8-bit mode then switching to 4-bit to save on wires etc… (so in total you only need 6 signals to talk to the LCD) and after some timing experimenting (clear screen command takes a while – over 1.5ms) as you can see I finally have a working LCD – and by the look of it, rock-solid reliable.

So what is driving that display (which is updating every second virtually instantly)…



and inside that inject?

Topic: freddy/toesp

Payload: {hitachi:39,"$1MQTT test$2$i$3Time $t$4Date $d"}

That’s all. So assuming you’re familiar with MQTT (if not – look at other articled in here) the destination is the little board “freddy” – and the new command I’ve just added – “hitachi” talks to an i2c board (the expander) device #39 and sends out that string.

Rather than have a boatload of commands which would be unwieldy in the home control setup – or special characters which might cause issues – I used the dollar as an escape character. Here’s what I’ve implemented up to now

  1. $$ -  well that shows a dollar on the screen !!
  2. $s -  setup – sets up a virgin LCD and clears the screen
  3. $c  - clear the screen
  4. $1 – set the cursor to line 1 -  ($2 $3 $4)
  5. $t  -  fire out the time
  6. $d – fire out the date
  7. $i  -  fire out the current ip address

I’ll probably settle on a 2-liner as they are sub-£2 from China – indeed for 20-off just over £1 – and at £1.34 for the port expander – around £3 to add a nice little display to some of the ESP8266 boards – can’t be bad. indeed, using one of the port expanders for an ultra-low-cost i2c keypad isn’t a bad idea. 45p for the keyboard, £1.34 for the expander… Sub-£2 keypad.

Clearly one way to wipe a line would be “$1               $1” which is probably fast enough for most purposes. I’ll likely think of some more commands.

A reminder that the right hand side of this blog contains links to the Home Control 2016 project, ROMs etc.

And now I have this big decision.. whether to spend £1.34 on a PCF-base port expander… which I need to poll regularly if attaching a keyboard – and no spare pins for a beeper – OR to spend £1.68 on an Arduino Nano which can be turned into an I2c peripheral (granted I might need 2 pull-up resistors) with keyboard buffering and a beep facility…..   OR…. go the whole hog and use another ESP8266 to make a completely wireless keypad.

OLED from SeeedAnd on that latter note – if you abandoned serial I/O which would net one more output – that gives up to 10 control pins – enough for a keyboard and beeper and light. Hmm…£1.43 for an ESP12, 17 pence for a 0.1” adaptor board.   Fully buffered keypad…. Big decision…

And finally – device 255 is reserved for  a PARALLEL version of this using 6 GPIO pins – 3,4,12,13,15 and 16 – operation is identical. All in the code – including the OTA ROMS. Documented in the WORD manual.

Update: On the right you see a Seeed OLED – I starting with this library, code intended for Arduino, I’ve heavily modified it to run in the normal ESPRESSIF SDK environment – but I have to say – the original Arduino version was SLOW, so VERY slow and this is still a little slow – especially the screen clear – I’ve pulled that into one function with an inner loop of I2c bytes, way faster than the original  but even THEN it is hardly nippy – but the important thing is that “Hello World” works – so soon I’ll add the above commands and then figure out a way to speed it up. Right now I can manage {seeed:”Hello world”} or similar. Current software and ROMs are on the web.


QD Tech Displays on the ESP8266

QDTECHI’ve seen a number of projects using an Arduino and an ESP8266 to drive LCD displays. You may know that my home control has used a 1284-based board (MEGA type) to run a nice Thermostat display for some time now. The displays look very pretty in the right box.

THIS article will tell you about the display but you’ve seen them on Ebay no doubt.

Banggood do the displays (I can’t help thinking the price has gone up – at £3 inc postage – but still cheap)

Anyway, they are 160*120 and very bright and colourful displays, excellent for simple stuff.

displayI’ve always wanted one of these to run on the ESP-12… on the Arduino assuming 5v you need series resistors for the outputs – as it’s a 3v3 device internally, but with an ESP you can run them directly. So, the device and it’s backlight go straight to 5v, the 4 inputs go straight to ESP8266 pins and the reset can go to the ESP8266 reset pin – again directly.

That’s the easy part – the software not so – there are not a lot of drivers out there for this board for the Arduino – one that does work offers a choice of hardware or software SPI and that’s where the magic comes in – if you eliminate the hardware SPI code it all starts to look quite easy. So yesterday I set about (with no anticipation of success) converting the code firstly from nicely object-oriented Arduino code – to basic C – and secondly to use ESP8266 port pins. I cheated slightly by using EASYGPIO to make the port operations a little more obvious but I don’t think that has cost too much in speed.

Anyway to cut a long story short at THIS point I’m off to the coast for a couple of days sunbathing and I’ll leave you with my work in progress. I’ve NOT added in the code to handle characters/fonts yet but I HAVE got this working completely reliably – drawing boxes and lines.  Right now there is some setup data in RAM, I’ll move that to FLASH shortly (you need a function to access 8-bit FLASH arrays to stop the ESP crashing so I left that until last). Why bother with FLASH? Well, you’ll definitely need to put fonts in FLASH as they get big, quickly.

I’m assuming you’re programming in C – don’t ask me about getting this running in Arduino code or Lua.

Here’s the header

Here’s the C code

I’ll assume you already have a project running and just want to add this to it. I’ve reduced includes to a minimum..

My test includes a red screen background, a green box and a blue diagonal line. So with the includes this is all I put in my code (I slightly altered the init code to include ports (not including RST line as you fasten that to the ESP reset – hence needing only 4 port bits – you’re not stuck with my choice – the last two parameters are the screen size).

for (int qq=0; qq<160;qq++) QD_drawPixel(qq,qq,QD_Color565(0,0,255));

There it is – a starter only.. but it works – if this were taken to an extreme it would include character handling and hardware SPI – I’m guessing compared to Arduino use it would be pretty FAST..

Now if anyone wants to take this on and add the bells and whistles..

Oh and how would you run the data in FLASH? not so hard… here’s a typical FLASH-based array snippet.

static const uint8_t ICACHE_RODATA_ATTR  kelvin[] = {
        255,  51,   0, //    1000
        255, 109,   0, //    1500
        255, 137,  18, //    2000

And to access that…

// This routine courtesy Richard A Burton - way better than using 32 bit flash arrays (you can't directly
// access 8 bit FLASH arrays directly - will crash the processor)
uint8 ICACHE_FLASH_ATTR read_rom_uint8(const uint8* addr){
    uint32 bytes;
    bytes = *(uint32*)((uint32)addr & ~3);
    return ((uint8*)&bytes)[(uint32)addr & 3];

Typical use;;;


So you can see it won’t be TOO hard to get a load of font data into FLASH – sure, it’ll slow things down a little accessing it – but how that actually affects operation is something we’ll discover in the future.