Deployment Beckons

moisture sensorPlease note – this blog is WELL out of date and all of my blog items and much, much more have now been moved to http://tech.scargill.net

’m now getting dangerously near the point where I have to DO something with all of this ESP8266 control stuff. We’re at the cave and I’ve a watering system to sort – a simple example – so one of the ESP012 boards has a relay on it and another has an ADC input. By the use a simple Node-red function combining timing and reading the ADC convertor (which is attached to a cheap Chines moisture sensor) and looking at the value coming out (already tongue-tested) I should be able to arrange to turn the watering system on and off twice a day – but also taking into account extreme levels of moisture either way (i.e. don’t’ bother watering the plants when it is pouring with rain… and give them a little extra when it is bone dry out there.

Continue reading

ESP8266 I2c

There seems to be chatter going around about how the ESP8266 does not have I2c.  So much so that there are implementations of bit-banged I2c out there..  here for example and this one is good for those with ESP-01 boards which only have 2 pins available – but beware that GPIO-0 is also used in hold-low mode on powerup for flashing the chips – and also the developer of this driver states that works needs to be done. I noted that it is NOT done under interrupts.

If you want to see the official line on i2c it is that it IS supported – here it is in the SDK documentation. http://www.esp8266.com/viewtopic.php?f=5&t=449  – available in both WORD and PDF versions…  granted this is early documentation 0.9.1– there is later (around December 0.9.4) but as far as I am AWARE you have to sign an NDA to get the newer information – I may be wrong.. you could check with Espressif themselves.

According to the documentation you have full I2c master control (it would have been nice had it specified which pins to use!)

It would be nice if someone would submit a really trivial I2c example using the above, stating which pins needs to do what.

What I don’t understand is – when ESPRESSIF distribute the various SDKs there’s a directory in there called document that is always empty – you would think they’d take the opportunity to include the documents in there!!

Of interest if you have the pins available there is also a dual UART (ie 2 lots of serial lines) and PWM control of some of the pins.

MQTT for ESP8266 not QUITE but nearly

Minh Tuan is doing an excellent job with MQTT – he has it working stand alone – and in the LUA code (not yet brought into the main code)… but..

Before you go off getting annoyed if things don’t go quite to plan, there still seems to be a tiny but important bug  -I’ve reported it today and Minh will look at it tomorrow. I’m working on code from just an hour ago here (late after noon UK)

I set up a demo, subscribing to 7 short topics. With the exception of the first, all the topic names are short… and all responses are short…. I’ve changed the broker name below to protect the innocent (that would be me).

MQTT: subscribe, topic"home/openHAB/out/Light_FF_Bath_Ceiling/command" at broker xxx.yyy.zzz:1884
MQTT: subscribe, topic"myleds" at broker  xxx.yyy.zzz:1884
MQTT: subscribe, topic"mytime" at broker home.scargill.org:1884
MQTT: subscribe, topic"time" at broker xxx.yyy.zzz:1884
MQTT: subscribe, topic"dusk" at broker xxx.yyy.zzz:1884
MQTT: subscribe, topic"dawn" at broker hoxxx.yyy.zzz:1884
MQTT: subscribe, topic"timestring" at broker xxx.yyy.zzz:1884

As you can see all of them subscribed successfully or so it would seem.

Ah, but…

4 of them are broadcast every minute from a page I demonstrated in a previous blog or it’s notes and over on another computer I have MQTT spy watching… time, dawn, dusk and timestring are send out by the same page once per minute.

But what is being seen by the little ESP8266 program is….

TCP: data received
MQTT topic: time, data: {1484956800}
TCP: data received
MQTT topic: timestring, data: {15:15 Saturday 17-01-15}
TCP: data received
MQTT topic: time, data: {1484956800}
TCP: data received
MQTT topic: timestring, data: {15:16 Saturday 17-01-15}

As you can see, dawn and dusk have “disappeared into the dusk”.

Similar happens with the Lua/MQTT code – I thought at first that might be due to the callback not being done before being called again but seeing this I’m thinking… no.

As soon as this one is resolved I’ll report back. It is important that the system can handle several simultaneous incoming messages and that it it reaches it’s limit, something obvious tells us that.   The info above is the minimum I would be sending to any module –ok of course I could merge them into one – but that’s not the point – I could not do that if they were coming from different sources.

Suggest looking in again tomorrow for any fixes…

If I go quiet, I’m off to Brussels for a couple of days for some EU business.

And there’s more… I reduced the number of subscriptions to 3..

MQTT: subscribe, topic"dusk" at broker xxx.yyy.zzz:1884
MQTT: subscribe, topic"dawn" at broker xxx.yyy.zzz:1884
MQTT: subscribe, topic"timestring" at broker xxx.yyy.zzz.org:1884
MQTT: Sending..type: 8,qos: 4
TCP: Sent
TCP: data received
MQTT: Sending..type: 8,qos: 4
TCP: Sent
TCP: data received
MQTT: Sending..type: 8,qos: 4
TCP: Sent
TCP: data received
TCP: data received
deliver_publish
MQTT topic: timestring, data: {16:43 Saturday 17-01-15}
TCP: data received
deliver_publish
MQTT topic: dawn, data: {27208}
TCP: data received
deliver_publish
MQTT topic: timestring, data: {16:44 Saturday 17-01-15}
TCP: data received

 

Couple of things of concern – firstly again it’s SAYING it has subscribed to 3 but it only taking two of them – the last 2 (that’s not a clue, wasn’t last 2 last time) but the messages are also a concern… “Sending..type:8 qos:4”   there ISN’T a qos 4 !!! Don’t know what that is about…

ESP8266 the unstoppable March of Progress

esp01I’ve been following the progress of this little chipset as you know since day one – having spend a year more developing skills at using horrible little NRF24L01 radios with as much indoor range as my legs – and Arduino Ethernet cards (which to be fair are WONDERFUL other than their need for a marriage-endangering WIRE), out of the blue came a little Chinese board with the potential to change everything. The ESP-01 showed much promise but very little reality at first. The instructions were in Chinese, the documentation was in Chinese or missing, people told me “there are these other boards for only a tenner that do so much more”.

And yet here we are today with much of that about to change. The new so called white ESP8266 board with it’s development “kit” for less than a tenner is winging it’s way to me now – and the ESP-12 boards are neat and even have approval stickers to keep people happy not to mention a health range of I/O.

There are now a range of boards, all cheap  (there is a question mark over the ESP-07 – not for the first time I’ve heard there are 2 versions one of which is “suspect”) – and the ESP-01 remaining, I think true to my original statement – the title of one of my blogs “the cheapest computer in the world”. At under £2 tell me I’m wrong. 1 plug in the wall power supply , one ESP-01, one cheap solid state relay and you have a functioning WIFI-controlled device – with the right software that is.

But like all such devices, software makes or breaks this dream and in recent weeks we’ve seen the emergence of the ECLIPSE environment for Windows – I’m sure there are many such environments for Linux – and others will blog about them – I’m not interested in the command line and haven’t been for a long time. Eclipse and the tremendous work by the fellow who set this all up for us – means everyone from expert to complete beginner can “have a go”.

This week however is a bit special – we have in one corner TUAN and his MQTT code – on the other corner we have ZERODAY and his LUA interpreter – ( I really should find out everyone’s proper names) and this weekend – they look like merging.  I’m hoping that the MQTT code will continue to be developed independently of LUA as I think there are uses for both. I DO have code that WORKS – it’s not just a promise. We have some great tools such as Esplorer for testing Lua and the AT command set.

I can’t tell you what is possible with the software and hardware out there – all I can tell you is what I’m doing and why – I hope my blogs up to date have given you all the links you need. For days now I’ve been testing the MQTT software – and as far as I can tell there is only one “bug” left of note and it’s not even a bug – it’s an inconvenience – something to “wrapped up” – essentially the code works – but it’ not too happy about empty messages. I expect right now that is being fixed and I am so grateful to so many authors who have communicated, helped, changed things – in the main for no commercial gain – because they love it.. it’s almost like the days of the first 8-bit micros – the rush of learning.  Meanwhile I got an email this morning to say that MQTT and LUA were merging and a test set of .BIN files was available.

So, despite a head that is spinning like a TOP due to flu, this afternoon I set up a test rig…  let me take you through that quickly… erm… it works but read on as you need the bits that come before it.

The plot so far:

In order to use MQTT as the base of your control system (in my humble version of this vastly diverse Internet of Things) you need an “MQTT broker” running somewhere and it needs to be reliable – ROCK SOLID. In my case I have a Synology Diskstation (the link is an example – mine is not white) and with a little help I got the free MOSQUITTO running on it – you could put this on an old PC, a Linux box – just about anything with a brain – but it needs to be reliable. There are services out there – the free ones they generally warn you not to rely on them – so I’m not going to – I’ll have my own thanks – I’ve talked about several variations elsewhere – at the end of it I went with Mosquitto.  My disk backup DISKSTATION is on 24-7 so it seemed the ideal place for this. As for testing Mosquitto on a PC – you are not going to beat the EXCELLENT MQTT-SPY.

So now a place to fire messages to – and a place to receive them from… and the software tools for ESP8266 to send and receive those messages – the sky is the limit. But what about issues people have had – swapping modes – you might need the time from a time server for your little board or some other info. Well, I found a way around that.   MOSQUITTO is on all the time – what is needed is for it to make available info to the little boards, be it time, lighting up time, perhaps other information.  I found a PHP library – the nice kind – the type you don’t actually have to understand to use.  Some time ago I documented a web page I was using to fire back time and other information – I used it as I found NTP time servers to be slow at times.  I have cheap web space with a provider much as many of you will – with CPANEL – which means I get all the benefits of using a reliable Linux based web service while staying within my pretty coloured boxes visual interface comfort zone (I’m sure there’s an abbreviation for that).

With such a setup you can write PHP pages like one that will send time messages for example and with the ability to run those pages on demand using CRON (doddle) you can make the time and over information available to your toys.

Here’s the deal.

<?php
require("../phpMQTT.php");

$mqtt = new phpMQTT("xxx.xxxx.org", 1884, "somenamePub");
if ($mqtt->connect(TRUE,NULL,"mymqttuser","mymqttpass")) {
            $locn="Europe/London";
            $lon=55;
            $lat=-2;
            date_default_timezone_set($locn);
            if ($_GET[‘loc’]!="") $locn= $_GET[‘loc’];
            if ($_GET[‘lat’]!="") $lat= $_GET[‘lat’];
            if ($_GET[‘lon’]!="") $lon= $_GET[‘lon’];
            $dateTimeZoneLocal = new DateTimeZone($locn);
            $dateTimeLocal = new DateTime("now", $dateTimeZoneLocal);
            $localDateTime = date("H:i l d-m-y", time());
            $localTime=strtotime($localDateTime);
           
            $mqtt->publish("time",$localTime,0);
            $mqtt->publish("timestring",$localDateTime,0);
            $sun_info = date_sun_info($localTime, $lon, $lat);
            foreach ($sun_info as $key => $val) {
                if ($key==’civil_twilight_end’) $mqtt->publish("dusk",$val %86400),0);
                if ($key==’civil_twilight_begin’) $mqtt->publish("dawn",$val %86400,0);
            }
    $mqtt->close();
}
?>

No knocking my coding please – I do not profess to be a PHP expert – indeed – can you think of decent extra publications this page could produce for the little gadgets? If so lets have those ideas! 

This web page connects to your MOSQUITTO or other MQTT broker and every minute (every week if you want – my choice of every minute – gadget turns on – worse case it waits a minute to know the time) I am here publishing 4 items – the TIME in standard seconds-since-1970 format, British lighting up time (DUSK) in seconds since midnight, DAWN in seconds since midnight and TIMESTRING for those with no space in their project to format the time. ANY of my gadgets can choose to subscribe to these  publications – or not. And as you can imagine I’m planning more publications – timed an otherwise. The server load of the above is irrelevant – I don’t see anyone’s provider griping about this.

So – the people I’ve been with keep my web pages up and running 24-7 and and have done for as long as I can remember – why would I not trust this info.

And all of this brings us around to LUA+MQTT – possible only since this morning!!!

Check this out. Sorry it’s not formatted.

mqtt = net.createConnection(net.TCP, 0)
— init mqtt client with keepalive timer 30sec
mqtt:mqtt("myid", 30, "mymqttuser", "Tmqttpassmakeitagoodone")

— on publish message receive event
mqtt:on("receive", function(conn, topic, data) print(topic .. ":" .. data) end)
— on connection event (all event inherit from net module)
mqtt:on("connection", function(con) print("connected") end)
mqtt:connect(1884,"mymqttserver.address")
— subscribe topic with qos = 0
mqtt:subscribe("time",0, function(conn) print("subscribe success") end)
— publish a message
— mqtt:send("/topic","hello",0,0, function(conn) print("sent") end)

print (node.heap())

mqtt:subscribe("temperature",0, function(conn) print("subscribe success") end)

mqtt:send("dusk","hmm",0,0, function(conn) print("sent") end)

THAT which you see above and the code to log into your access point (which, once entered should stay there) is it – that code is all I had to put in – to have the little board be subscribing to time, dusk, dawn and temperature from another device (oh – a pair of minuses means comment – you need to see how to publish).

The REST is what you do with such info – Lua has timers (to keep that time going if you lose the internet connection) and GPIO control – to do things – already discussed previously – I’ve had a solid state relay running directly off the board and powering a mains lamp.

And that is it for now – the information isn’t here – it’s out there – check out the links here and in my previous blogs and bear in mind that before Christmas I knew NOTHING about compiling this stuff and I was determined determined not to get into Linux (and still successfully avoiding it)  – I’m now just about ready to openhabproperly embark on some real projects with real control in the comfort of my pretty-coloured Windows environment…  I hope that by putting all of this in one place gives you a head start.

For my next challenge – OpenHab but I think I’ll wait until the flu has gone – this one’s not going to be easy.

ESP8266 MQTT Publications

The PlanIn my last blog I referred to publishing temperature etc and there is one issue with the existing MQTT library that makes that an issue: The MQTT publications are not queued.

For the benefit of anyone still not into the MQTT thing – by publications I mean “sending a message” comprising a topic and a message. The topic might be “BathroomTemperatureReading” and the message might be “20.6”.

What happens right now – and Tuan has said he’ll fix this… if you send 2 messages out in a row IMMEDIATELY after each other – only the last one will go. Well, that’s fine unless you have to send one message off to a thermometer display and another message off to a humidity display.

So… this evening I wrote a queue. This is possible because of a “callback routine”. When you fire a message off it is handled in the background and when it’s done it calls an empty routine. I’ve trapped that.. the basic idea is this.  

Clear a “done” flag at the start and from there on..

If the done flag is clear, set it and send out a publication. If it is NOT clear, put the message in a queue.

In the callback routine, clear the flag – check a queue, if there is anything to go – send out the publication.

Simple really.

So here’s the code I’ve added to the start of the MQTT package..

#define QUEMAX 10  // 10 messages -  need more? – increase
#define QUESIZE 50 // my topics and messages are never more than 50 chars
struct Queues{
    MQTT_Client* cli;
    char top[QUESIZE];
    char mes[QUESIZE];
};

struct Queues myQueue[QUEMAX];

int queuein=0;
int queueout=0;
int isPublished=0; // my flag to see if I can publish or need to put in a queue

All simple enough – the queue can be maximum 10 deep (it’s rotary – when I get to the end I roll around to the start). I save the client pointer, the topic text and the message text in an array of simple structs.

At the beginning both the in pointer and out pointers for the queue are cleared and isPublished is clear.

Instead of the main publish routine – I have my own – which checks the flag before sending off a message.

void petesPub(MQTT_Client* cli, char *top, char *mes)
{
if (isPublished==0)    { isPublished=1; MQTT_Publish(cli, top,mes,strlen(mes), 0, 0); }
else
    {
    myQueue[queuein].cli=cli;
    strcpy(myQueue[queuein].top,top);
    strcpy(myQueue[queuein].mes,mes);
    if (++queuein>=QUEMAX) queuein=0;
    }
}

You can see the message going in the queue unless the flag is clear… and in the callback routine, called when a message has gone…

void mqttPublishedCb(uint32_t *args)
{
    MQTT_Client* client = (MQTT_Client*)args;
    INFO("MQTT: Published\r\n");
    isPublished=0;
    if (queuein!=queueout)
    {
        petesPub(myQueue[queueout].cli,myQueue[queueout].top,myQueue[queueout].mes);
        if (++queueout>=QUEMAX) queueout=0;
    }
}

The first two lines were there already – I don’t think I actually need to store the client info – I think it gets passed – however – what I have works for now.

So you can see I clear the published flag, look to see if there is anything in the queue and if there is – publish it. I’m sure there’s a bit of recursion going on there – but it all works.

And that’s me done for the day. Meetings again this week so I’ll not get much more done now until the weekend but DHT22, RTC and message queue – not a bad start for the week.

I’m still begging anyone with assembly skills to look at the WS2812B code to see if they can make an accurate job of it Smile

ESP8266 Memory Usage

debugGlen Cook has just made a neat little utility for checking the amount of RAM in Eclipse projects…  here’s the output – and there’s a link below – contact Glen, not me for more info.

Part of the problem of working with new processors – is understanding what is being used and where.  I look forward to seeing a visual version of this with used RAM, FLASH etc. and showing what’s used and what’s left. It would not be the first time I’ve run out of RAM.

http://www.betgear.biz/MemUsage.rar

Also linked to on my ESP8266 Facebook page.

Does anyone know the significance of the IRAM (initialised RAM) as in one project I’m down to 800 bytes – while having 38K of general RAM left.

ESP8266 Timers

Work today but I got up early and decided to take a break from solving the WS2812b issue – I’m getting a wide pulse at the beginning of every package caused by compiler optimisation and I cannot at this point figure a way around it (apart from using an Arduino to handle the serial LEDs which is cheating a bit). I figured I’d take a look at more leisurely timing.

Here’s an example use of a timer.

So you want to send a signal to the ESP8266 and you want to read the temperature.  Two things here.. the temperature reading is not instant – so every time you want a reading you have to call the temperature sensing routine.. wait for it – and then return the result. That is time wasted. How often does temperature change? Well, seriously I cannot imagine one wanting in a typical domestic or external environment,  to take readings more than, say every minute.. or even 5 minutes but here we are polling away and wasting time.

A better way then is to check the temperature every now and then – store the result.. and your polling operation merely reads the values.

But how do you set timers going in ESP8266.  I’m not going to pretend to be an expert – I simply took code from another example and put it into my project – and it works.

So – reading the temperature every 30 seconds

You’ll need temperature sensing software.

Up at the top of your program where your init stuff is..

#define LED_GPIO 2
#define LED_GPIO_MUX PERIPHS_IO_MUX_GPIO2_U
#define LED_GPIO_FUNC FUNC_GPIO2

float temperature,humidity;

#define DELAY 30000 /* milliseconds for temperature */

in the init() routine set up GPIO2

PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);
PIN_PULLUP_EN(PERIPHS_IO_MUX_GPIO2_U);

#define LED_GPIO 2
#define LED_GPIO_MUX PERIPHS_IO_MUX_GPIO2_U
#define LED_GPIO_FUNC FUNC_GPIO2

float temperature,humidity;

#define DELAY 30000 /* milliseconds for temperature */

in the init() routine set up GPIO2

PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);
PIN_PULLUP_EN(PERIPHS_IO_MUX_GPIO2_U);

and here’s a routine to read temperature and humidity and store them in variables of that name. I didn’t write this..

#define MAXTIMINGS 10000
#define BREAKTIME 20
static void ICACHE_FLASH_ATTR readDHT()
{
    int counter = 0;
    int laststate = 1;
    int i = 0;
    int j = 0;
    int checksum = 0;
    //int bitidx = 0;
    //int bits[250];

    int data[100];

    data[0] = data[1] = data[2] = data[3] = data[4] = 0;

    GPIO_OUTPUT_SET(2, 1);
    os_delay_us(250000);
    GPIO_OUTPUT_SET(2, 0);
    os_delay_us(20000);
    GPIO_OUTPUT_SET(2, 1);
    os_delay_us(40);
    GPIO_DIS_OUTPUT(2);
    PIN_PULLUP_EN(PERIPHS_IO_MUX_GPIO2_U);

    // wait for pin to drop?
    while (GPIO_INPUT_GET(2) == 1 && i<100000) {
          os_delay_us(1);
          i++;
    }

        if(i==100000)
          return;

    // read data!

    for (i = 0; i < MAXTIMINGS; i++) {
        counter = 0;
        while ( GPIO_INPUT_GET(2) == laststate) {
            counter++;
                        os_delay_us(1);
            if (counter == 1000)
                break;
        }
        laststate = GPIO_INPUT_GET(2);
        if (counter == 1000) break;

        //bits[bitidx++] = counter;

        if ((i>3) && (i%2 == 0)) {
            // shove each bit into the storage bytes
            data[j/8] <<= 1;
            if (counter > BREAKTIME)
                data[j/8] |= 1;
            j++;
        }
    }

/*
    for (i=3; i<bitidx; i+=2) {
        os_printf("bit %d: %d\n", i-3, bits[i]);
        os_printf("bit %d: %d (%d)\n", i-2, bits[i+1], bits[i+1] > BREAKTIME);
    }
    os_printf("Data (%d): 0x%x 0x%x 0x%x 0x%x 0x%x\n", j, data[0], data[1], data[2], data[3], data[4]);
*/
    float temp_p, hum_p;
    if (j >= 39) {
        checksum = (data[0] + data[1] + data[2] + data[3]) & 0xFF;
        if (data[4] == checksum) {
            /* yay! checksum is valid */

            hum_p = data[0] * 256 + data[1];
            hum_p /= 10;

            temp_p = (data[2] & 0x7F)* 256 + data[3];
            temp_p /= 10.0;
            if (data[2] & 0x80)
                temp_p *= -1;
            temperature=temp_p; humidity=hum_p;
        }
    }
}

So now you have a routine you can call and it will return the temperature – oh- you’ll need a DHT22 (NOT the DHT11) attached to ground, GPIO2 and 3v3. And put a capacitor, maybe 10uf across the power right next to the DHT-22. Occasionally especially with longer leads or poor power regulation I find they simply won’t respond without this.

How to get that routine ( readDHT() ) to call every 30 seconds – so that you can simply read the 2 variables temperature and humidity – at your own leisure…

Doddle.

Put this at the top of your program

LOCAL os_timer_t temperature_timer;

Put this in your init…

os_timer_disarm(&temperature_timer);
os_timer_setfn(&temperature_timer, (os_timer_func_t *)temperature_cb, (void *)0);
os_timer_arm(&temperature_timer, DELAY, 1);

and put your temperature reading in this routine..

LOCAL void ICACHE_FLASH_ATTR temperature_cb(void *arg)
{
    readDHT();
}

and that… is that – every 30 seconds it will go take a temperature reading. If you need the temperature straight after power up you might want to do a one-off call to readDHT() in the init() routine  as it’s not going to get a value for 30 seconds. And where did all of that come from? Merely by studying the BLINKY example in the Eclipse environment for Windows.

So now I have a little ESP01 which can respond to MQTT, which can turn a light or solid state relay on and off, which can read the temperature and which can ALMOST set up a line of WS2812B chips – – I just need someone further down the learning curve than I to help me solve the compiler optimisation issues with WS2812B writing.

You can see where this is going can’t you.. yup – next stop – real time clock timer -  a 1 second RTC which could be updated by an MQTT message.

Now there IS an RTC inside the ESP8266 chips – and one of the boards supports it – the new white ESP8266 board has a clock crystal – however as that needs ESPRESSIF to tell us how it works and as that ALSO needs pins which we don’t have on some of the boards including the popular ESP-01 – we’ll ignore that for now and do our own thing.

The question is – how accurate would such a real time clock be – it’s going to get updated by messages every now and then but still it would be good if it could last a couple of days or so without being updated.

Here we go…

More setup

LOCAL os_timer_t rtc_timer;
unsigned long myrtc=0;

More init

os_timer_disarm(&rtc_timer);
os_timer_setfn(&rtc_timer, (os_timer_func_t *)rtc_cb, (void *)0);
os_timer_arm(&rtc_timer, 1000, 1);

more function…

LOCAL void ICACHE_FLASH_ATTR rtc_cb(void *arg)
{
    ++myrtc;
}

To LED or NOT to LED

ledAt the time I started writing this at 11.33am this morning I had already demonstrated one of my little boards running MQTT and a LED in one case and a mains bulb in the other. Now it’s time to move on. I put a request out this morning if anyone had some code to handle the serial LEDs and indeed as part of a bigger project someone did. The code really is simple – it’s the timing that’s the thing.  The serial LEDS have 4 wires (avoid the older ones). Power (5v), ground, in and out. You daisy chain them – out from one into the input of the other.

I’ll not go into timings here but a wide pulse to the input of the first LED resets them all so they are ready to receive information. A series of pulses comprising R G B information (1 byte each) sets up the first LED. It then passes on everything it sees to the next one – buffered. By this simple but ingenious leap of faith (who at one point would have put a microchip inside of a LED) we end up being able to control endless (almost anyway) LEDs on one wire. If you want them all the same – it’s a doddle – if you want to send a complete sequence so each  LED is a different colour – well you have to have an array to store the values. In this case I’m interested only in making them the same colour – for lighting – but I have to start with what’s available.

So at this point I assume you have an MQTT broker and you can get a board talking to it. I also assume you have the Eclipse environment on your PC and you can compile the MQTT code and FLASH it. No other assumptions are made. So what you are looking at above is one of my development boards with an ESP-01 sitting in it – all the board is for is to allow me to plug in an FTDI for programming – and to run 5v to the board – it has a regulator and a voltage shifter (2 resistors) for the serial INPUT to the board – no need to level shift output to the FTDI.

Below it is a board we had made to house 10 of the serial LEDs – I think ADAFRUIT do a range of boards or you can just buy the strip from Ebay. 3 leads – gnd, 5v and  signal. IN THEORY they run from 3v3 but I’ve no big sources of 3v3 power so once I get this working I’ll try 5v. For now – this hooks to GPIO-0 (when it’s not grounded for programming) and 3v3 and GND.

I am starting with the basic MQTT software and I’m making a topic “firstLedStrip” just because I can – I could have called the topic “pete” – matters not.   I plan to be able to send 255,255,255 for white and MAYBE another parameter for the number of LEDS… I don’t need individual LED colouring… but the principle is the same… Let’s go for getting one light working THEN get ambitious.

This is my version of the code that Markus pointed me to and it’s almost identical – just changed it a little for experimentation. Now I have TWO issues I hope you guys can help me with.. they may or may not be related.. here’s an opportunity for someone to shine..

 

#define WSGPIO 0

static void ICACHE_FLASH_ATTR send_ws_0()
{
  uint8_t i;
  i = 4; while(i–) WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_ID_PIN(WSGPIO), 1);
  i = 9; while(i–) WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_ID_PIN(WSGPIO), 0);
}

static void ICACHE_FLASH_ATTR send_ws_1()
{
  uint8_t i;
  i = 8; while(i–) WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_ID_PIN(WSGPIO), 1);
  i = 5; while(i–) WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_ID_PIN(WSGPIO), 0);
}

static int ICACHE_FLASH_ATTR gpio_ws2812( char *buffer, int length )
{

  GPIO_OUTPUT_SET(GPIO_ID_PIN(WSGPIO), 0);

  os_intr_lock();
  const char *end = buffer + length;
  while( buffer != end ) {
    uint8_t mask = 0x80;
    while (mask) {
      (*buffer & mask) ? send_ws_1() : send_ws_0();
      mask >>= 1;
    }
    ++buffer;
  }
  os_intr_unlock();

  return 0;
}

#define WSGPIO 0

static void ICACHE_FLASH_ATTR send_ws_0()
{
  uint8_t i;
  i = 4; while(i–) WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_ID_PIN(WSGPIO), 1);
  i = 9; while(i–) WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_ID_PIN(WSGPIO), 0);
}

static void ICACHE_FLASH_ATTR send_ws_1()
{
  uint8_t i;
  i = 8; while(i–) WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_ID_PIN(WSGPIO), 1);
  i = 5; while(i–) WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_ID_PIN(WSGPIO), 0);
}

static int ICACHE_FLASH_ATTR gpio_ws2812( char *buffer, int length )
{

  GPIO_OUTPUT_SET(GPIO_ID_PIN(WSGPIO), 0);

  os_intr_lock();
  const char *end = buffer + length;
  while( buffer != end ) {
    uint8_t mask = 0x80;
    while (mask) {
      (*buffer & mask) ? send_ws_1() : send_ws_0();
      mask >>= 1;
    }
    ++buffer;
  }
  os_intr_unlock();

  return 0;
}

 

See the code above – sends out an array to GPIO0. Ok, so I could send something like this.

char bar[3] = { 255, 0, 255 };
gpio_ws2812( bar,3);

And…. the FIRST LED lights up – if I send twice as much..

char bar[6] = { 255, 0, 255 ,4,5,6};
gpio_ws2812( bar,6);

 

TWO LEDS light up – Wheeeeeeeeeeeeeeeeee… except they’re lighting up WHITE and not taking ANY notice of the colours.

 

SO – why did I add ICACHE_FLASH_ATTR to the function calls – because without that – MERELY ADDING TWO of those functions brought back this reponse from the compiler… (this is added to the standard MQTT library).

 

13:30:37 **** Build of configuration Default for project mqtt_pub_ps_ser ****
mingw32-make.exe -f C:/Users/Peter/workspace/mqtt_pub_ps_ser/Makefile all
CC user/user_main.c
AR build/app_app.a
LD build/app.out
c:/espressif/xtensa-lx106-elf/bin/../lib/gcc/xtensa-lx106-elf/4.8.2/../../../../xtensa-lx106-elf/bin/ld.exe: build/app.out section `.text’ will not fit in region `iram1_0_seg’
collect2.exe: error: ld returned 1 exit status
C:/Users/Peter/workspace/mqtt_pub_ps_ser/Makefile:128: recipe for target ‘build/app.out’ failed
mingw32-make.exe: *** [build/app.out] Error 1

13:30:38 Build Finished (took 734ms)

 

WHY? Are we that near the limit – I am assuming the changes I made put the routines into FLASH  -why would I be running out of RAM for heavens sake and how do I get around that.

That’s the first problem – adding the highlighted info it all compiles and KIND OF WORKS.

Next problem – possibly related possibly not – take THE FIRST example..

char bar[3] = { 255, 0, 255 };
gpio_ws2812( bar,3);

I trigger this off with a publication – and it works a treat every time – one light lights up but it’s supposed to be purple – it’s always WHITE. Here’s what actually goes out thanks to my remarkably cheap Saleae logic analyser…

Output GPIO0 normally low – here’s the package.

Image635565800289650314

Looks good to me – you can see the 255, then the 000 then the 255. Here’s a zoom for timings… of the 255…

255

and the 0

0

 

So  some updates for you at 15:11 -  the timings WERE miles off – someone said this might be to do with compiler settings – I have no idea how to alter those. I’m using the default settings… I started messing with the settings and could get colours (We’re talking WS2812B LEDS here with 1 timings of 0.9us high then 0.35us low – and 0 timings of  0.0.35us high then 0.9us low

This is the nearest I can get without changing the whole lot into assembly – which isn’t a bad idea if anyone wants to chip in.

Finally it did not help I was expecting RGB order whereas in fact the serial stream is GRB order…Here is what I finally ended up using – I put the ICACHE_FLASH_ATTR elsewhere and that issue still needs resolving or it’s going to come back over and over.

#define WSGPIO 0

/*

static void  send_ws_0()
{
  uint8_t i;
  i = 4; while(i–) WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_ID_PIN(WSGPIO), 1);
  i = 9; while(i–) WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_ID_PIN(WSGPIO), 0);
}

static void  send_ws_1()
{
  uint8_t i;
  i = 8; while(i–) WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_ID_PIN(WSGPIO), 1);
  i = 5; while(i–) WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_ID_PIN(WSGPIO), 0);
}
*/

static void  send_ws_0()
{
  uint8_t i;
  WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_ID_PIN(WSGPIO), 1); for (i=0;i<1;++i);
  WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_ID_PIN(WSGPIO), 0); for (i=0;i<2;++i);
}

static void  send_ws_1()
{
  uint8_t i;
  WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_ID_PIN(WSGPIO), 1); for (i=0;i<6;++i);
  WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_ID_PIN(WSGPIO), 0);
}

static int  gpio_ws2812( char *buffer, int length )
{

  GPIO_OUTPUT_SET(GPIO_ID_PIN(WSGPIO), 0);

  os_intr_lock();
  const char *end = buffer + length;
  while( buffer != end ) {
    uint8_t mask = 0x80;
    while (mask) {
      (*buffer & mask) ? send_ws_1() : send_ws_0();
      mask >>= 1;
    }
    ++buffer;
  }
  os_intr_unlock();

  return 0;
}

And with that and the call…

if (strcmp(topicBuf,"myleds")==0)
    {
        char bar[9] = { 0, 255, 0,255,0,0,0,0,255 };
        gpio_ws2812( bar,9);
    }

we get….

rgb

 

Wheeeeeeeeeeeeeeeeeee…

 

BUT the FIRST light is only correct on the second invocation – so I’m assuming I need that port initialisation in my INIT file and the port sent LOW (hence ensuring reset).. I’ll do that next – and then having already identified the topic I need to parse “xxx,xxx,xxx” into 3 numbers, pop them in – and we’re off!! IDEALLY I’d like a 4th parameter, dynamically allocate the number of LEDS in the way I did in the FASTLED modification – but how to MALLOC in here is anyone’s guess – I need some means to tell me now much RAM I have left.

In case you’re panicking – when I get this going I’ll detail the changes needed to the existing MQTT code to get this far – you WILL need to be able to compile – and that is why I’ve asked the designer of the MQTT package ot consider setup via the serial port for Access point, MQTT Broker and subscriptions as that would make it possible for people to use the package with, say and Arduino without having to compile.  Time will tell, I may learn how to do that myself.

More later – and now to try the whole 10 LEDS – I really like pushing my luck.

 

15:48 – I’ve now put “    GPIO_OUTPUT_SET(GPIO_ID_PIN(WSGPIO), 0); // for LEDS” into the INIT function to set the output on power up – and having put in the compiler optimisation as suggested by GREG – the speed has gone right up so that the original settings were almost right..

Here’s what I’ve ended up with..

static void  send_ws_0()
{
  uint8_t i;
  i = 4; while(i–) WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_ID_PIN(WSGPIO), 1);
  i = 9; while(i–) WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_ID_PIN(WSGPIO), 0);
}

static void  send_ws_1()
{
  uint8_t i;
  i = 10; while(i–) WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_ID_PIN(WSGPIO), 1);
  i = 3; while(i–) WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_ID_PIN(WSGPIO), 0);
}

HOWEVER that first red led is very hit and miss – as I trigger off the update – it takes a few attempts.  At first attempt it’s orange – then maybe after 3 or 4 goes I get RED.. something still not quite right..

Looking at the graph I’m getting a wide pulse at the very start – I have NO idea why… if I send 2 packages it’s still the same…

wide

 

16:32 I’m having a break – WITH the ESP8266 compiler  optimisations the guys have suggested – I cannot get rid of that wide pulse at the start. WITHOUT the optimisations, the ‘1’ state ZERO is too wide…

Time for a coffee and relax before I hit something.

ESP8266 and RB Serial LEDS

rgb ledsWell, it looks like everyone and their auntie have figured out how to get Arduinos to listen to ESP8266s sending out messages and control RGB serial LED strips – not surprising as there are several Arduino (and for other boards) serial libraries out there. I’m not talking about old fashioned 12v RGB strip but the more modern 5v variety with serial control, which, when (if) they get the price down, HAS to be the future of lighting.

I was at a hotel in Blackpool a few weeks ago and they’d just modernised and had the serial LED strip EVERYWHERE. If you’re not familiar with this stuff, each LED has a serial controller and can accept RGB settings – and once set can simply pass the info to the next LED. All of this is done with blindingly fast serial, so fast they build huge TV displays at airports using the stuff. Why is this stuff so much better than the old PWM red then green then blue LEDS? Because all 3 chips are in one housing you can create REALLY subtle lighting – you want daylight? No problem Tungsten? No problem? Nice warm candle-light? No problem.

Grab a strip, fasten it to an Arduino, provide plenty of 5v and a library and you’re up and running. You tell the library how many LEDS you have and it builds an array of 3 bytes for each LED. You populate the RGB info for the LEDS, call a function and BANG – they all get updated in an instant. with that array at hand it is trivial to write code to drive a colour wheel through it and by updating at regular intervals, create a moving colour change along the strip that is nothing short of stunning.

Right – that’s the easy way and also the larger and more expensive way. Now when is some clever person going to provide us with the same library (in C, not Lua please) for the ESP8266. Should not be a problem as the chip is way faster than an Arduino. I am not familiar enough with the chip to do this yet but I’m hoping someone else is – or has already done this – any takers?

Add this to the current MQTT code and you have an instant WIFI lighting controller. If antone has this or can make this I’m quite happy to put an article together – once I have my hands on a library (preferably working with GPIO0 or GPIO2 on the ESP-01 as that’s the cheapest and smallest solution out there but is pin-challenged).. it’ll take me no time to get that under message control.

ESP8266 MQTT Success

3v3In a previous blog I was starting to get a little depressed having discovered MQTT and having figured out how to get a light to turn on and off using MQTT and Openhab, I was gutted to find it would not work when I put everything together. By everything I mean a power supply, an ESP-01 and a solid state relay. No matter what I did it would not work – I received lots of helpful advise from readers and putting everything together solved the problem.

The original idea was to use a cheap Chinese 3v3 supply – feeding the ESP8266. That in turn would feed a solid state relay.

2 mistakes:  (1) the power supply was CRAP – electrical noise, dangerous mains connection – so much noise it would not let the board work. I tried going back to the bench supply – sure enough I could talk to the board but that’s when I discovered the second error (2) – connecting the relay to ground and the output of the ESP-01 – NO.

final prototype boardThe two changes I made were as follows – reference the relay to 3v3 and the output – not ground and the output. As for power – on my second attempt I used a cheap Chinese 5v supply and used a 3v3 regulator to get rid of the noise. Works a TREAT!

So now I’m right at the beginning. I have the following setup:

Mosquitto (free – runs on a variety of platforms) on a reliable NAS unit – acting as a message broker.

OpenHab (free – runs on a variety of platforms) running on a PC, soon to run on the same reliable NAS unit, processing rules and generally holding everything together.

ESP01 as an end controller – right now it turns a light on and off – soon  it will report on temperature and humidity – and control RGB LEDs (someone else will have to write that function).

lampAnd I’m testing with mqtt-spy which is wonderful and many thanks to the designer who has made many changes at my request. The long and short of it – this all WORKS, it works reliably and it’s a practical solution with SO many possibilities and for the first time also reasonably SECURE!

Did I make my own controller with lots of power taking months to develop with networked radios etc, does it work in 3 properties utterly reliably? Is it likely to go in the bin in the next few months? Yes to all of that.

The new power supply despite being cheap from China is a different thing ALTOGETHER to the first on – you can see just looking at it – slots in the board between the two power lines, a slot between the live side and the hopefully not  live side… way better bet and it’s able to give the better part of an amp at 5v.

powerThings to do – the ESP01 connects to a single access point – it is useless when you take it to another part of the building with a different access point – it needs to have a list of access points and passwords – go get a list of what’s available and pick the strongest of the signals that is in the list I provided.  Anyone up to writing that?

Also need more functions – switching a light on and off is hardly exiting – controlling RGB LEDS on the other hand IS.

I will follow this up with more detail but I’ve had enough for one day and I thought you might like to see that this is going somewhere.