Category Archives: IOTManager

IOT Manager Revisited

This started off as a very short blog some time ago – you’ll see  comments below but I’ve re-written it. I occasionally like to revisit stuff I have reviewed or played with ages ago because, well, things change. Had I not persevered with ImperiHome I would not now have a perfectly good IOT controller on my phone as originally it did not support Node-Red (Peter Oakes and I soon fixed that - documented elsewhere) and that package is now my preferred central control tool (the fact that it is now bog-standard fitment on the world’s most popular SBC – the Raspberry Pi – is another good reason to stick with it).

(Some regular readers may ask – what happened to BLYNK? – well,  it is still running back in the UK reliably – has been doing so for nearly 6 months – I just happen to prefer Imperihome).

IOT ManagerSo, IOT Manager is a weird one – the programming is different to many of the systems out there which try to be all things to all people – supporting endless devices many of which will no doubt bite the dust in time and it is not yet as advanced as either Blynk or Imperihome, but the author is keen – has done a LOT of changes for me and is rapidly approaching the point where it will compete with the likes of Imperihome.

http://esp8266.ru/iotmanager/

Let me say that at the time of writing you need the BETA version of IOT Manager to get the best out of it. Joinging the beta program is trivial.

So on first revisiting IOT Manager, could I HELL remember how to use it.  One of it’s original “features” was support for websockets for MQTT – fine – but it ran rather slowly and I think that’s one reason I abandoned it – so when I noted that it now also supports MQTT directly – with username and password – and figured I’d give it another shot.

So I loaded up the Android App and filled in my MQTT broker details and… nothing. Try as I might I could not figure out how to add a widget. All I had was a screen that said “no data” and a green indicator showing that it was indeed connected to my MQTT server (public address). It didn’t help that the website went on about Arduinos and stuff and really didn’t seem to get to the bottom of how to quickly get started if you didn’t have one of those. The documentation has still not quite caught up with developments.

ChartHaving loaded up IOT Manager there are no settings on the phone to create widgets  – instead, MQTT messages tell it what to do and YOU send those from, for example Node-Red! It’s really easy once you get past that hurdle.

So how the package NOW works is to initially send out a request for updates on the number and details of pages needed – and to ask for details of widgets required.

From then on the phone will request updates on specific page widgets as and when a page is selected or focus is lost. This minimises the information that needs to be sent.

When a button is pressed the info is sent back from the App by MQTT. I’ve chosen to process all of this with Node-Red. Plain NodeJS would no doubt do just as well.

Here is a list of the current widgets which includes sliders and power buttons as well as toggles…

  •       anydata
  •       simple-btn
  •       display-value
  •       small-badge
  •       power-button
  •       range
  •       toggle
  •       SteelSeries
  •       fillgauge
  •       chart

The CHART widget is new and I’ve not yet had time to test it but here’s an example on the right above.

In the example below I have three pages (named page1, page2 and page3). On the first page are two switches and a slider (range7). On the second are 3 level gauges and on page 3 are a couple of thermometer-type displays.

IOT Manager - my Node-Red code - Peter Scargill

This is what they look like…

1[4]  2[4]  3

What we have here is an APP that connects to your MQTT server (or a public one) and at that point sits and does nothing.

Essentially once the phone is connected it is listening to an MQTT subscribe. Your controller – say, Node-Red on a Raspberry Pi or even a simple ESP8266 (but you still need an MQTT broker either locally or a publically-available broker)  when it turns on and connects to the same MQTT broker, sends some init code and magically a bunch of controls appear on the phone – you can then use the controls and they send out info back to Node-Red or whatever you want to use as a central controller. What is great about this is that it could be dynamic – as this is set at the control end, not the App end.

I centralise everything via Node-Red which of course can publish and subscribe to MQTT and then control my devices from there. I decided to write the code for Node-Red to give others a starting point.

So you can see in the diagram above the two SUBSCRIBES. That info is passed to a couple of functions – here they are…

var topic=msg.topic.split("/")[3];
global.set("IoTmanager_" + topic,msg.payload);

And now the second function...

var prefix = "/IoTmanager";
var deviceId = "bedrock";
var config = [];

var pagesList = {
    pages: [
        { pageId: 10, pageName: "page1" },
        { pageId: 20, pageName: "page2" },
        { pageId: 30, pageName: "page3" }
    ]
};

var id = "0";
var widget="toggle";
  config[0] = { 
  id : id,
  page: pagesList.pages[0].pageName, 
  pageId: pagesList.pages[0].pageId,
  descr : "pump 1",
  widget : widget,
  itemstyle : "",
  itemclass : "",
  topic: prefix + "/" + deviceId + "/" + widget + id,
  color : "orange",
  style : ""
};


  id = "1";
  widget="toggle";
  config[1] = {
  id : id,
  page: pagesList.pages[0].pageName,
  pageId: pagesList.pages[0].pageId,
  descr : "pump 2",
  widget : widget,
  style1 : "",
  class1 : "",
  topic: prefix + "/" + deviceId + "/" + widget + id,
  color : "blue",
  style : ""
};

  id = "7";
  widget="range";
  config[7] = {
  id : id,
  page: pagesList.pages[0].pageName,
  pageId: pagesList.pages[0].pageId,
  descr : "range 1",
  widget : widget,
  topic: prefix + "/" + deviceId + "/" + widget + id,
  color : "blue",
  style1 : "\"style\":\"range-balanced\"",   
  badge1 : "\"badge\":\"badge-balanced\""
};


  id = "2";
  widget="fillgauge";
  config[2] = {
  id : id,
  page: pagesList.pages[1].pageName,
  pageId: pagesList.pages[1].pageId,
  widget : widget,
  class1 : "item no-border",
  style1 : "",
  descr  : "Water level",
  class2 : "light text-center",
  style2 : "font-size:24px;font-weight:bold;padding-bottom:5px;",
  topic: prefix + "/" + deviceId + "/" + widget + id,
  width  : "150",
  height : "150",
  class3 : "text-center",
  style3 : "",
  widgetConfig : {
  }
};

  id = "3";
  widget="fillgauge";
  config[3] = {
  id : id,
  page: pagesList.pages[1].pageName,
  pageId: pagesList.pages[1].pageId,
  widget : widget,
  class1 : "no-border text-center col-xs-4",
  style1 : "",
  descr  : "Fuel level",
  class2 : "assertive text-center",
  style2 : "font-size:14px;padding-bottom:5px;",
  topic: prefix + "/" + deviceId + "/" + widget + id,
  width  : "70px",
  height : "70px",
  class3 : "text-center",
  style3 : "",
  widgetConfig : {
    circleColor : "#FF7777",
    textColor : "#FF4444",
    waveTextColor : "#FFAAAA",
    waveColor : "#FFDDDD",
    circleThickness : 0.2,
    textVertPosition : 0.2,
    waveAnimateTime : 1000
  }
};

  id = "4";
  widget="fillgauge";
  config[4] = {
  id        : id,
  page: pagesList.pages[1].pageName,
  pageId: pagesList.pages[1].pageId, 
  widget    : widget,
  class1    : "no-border text-center col-xs-4",
  style1    : "",
  descr     : "Water level",
  class2    : "energized",
  style2    : "font-size:14px;padding-bottom:5px;",
  topic: prefix + "/" + deviceId + "/" + widget + id,
  width     : "70px",
  height    : "70px",
  class3    : "text-center",
  style3    : "",
  widgetConfig : {
    circleColor : "#D4AB6A",
    textColor : "#553300",
    waveTextColor : "#805615",
    waveColor : "#AA7D39",
    circleThickness : 0.1,
    circleFillGap : 0.2,
    textVertPosition : 0.8,
    waveAnimateTime : 2000,
    waveHeight : 0.3,
    waveCount : 1
  }
};

    id = "5";
    widget="steel";
    config[5] = {
    id     : id,
    page: pagesList.pages[2].pageName,
    pageId: pagesList.pages[2].pageId,
    descr  :"Steel 1",
    widget : widget,
    topic: prefix + "/" + deviceId + "/" + widget + id,
    widgetConfig : {
    width  : "auto",
    height : 100,
    type   : "Linear",
    titleString: "Thermometer 1",
    unitString : "temp C",
    threshold: 90
}
};

    id = "6";
    widget="steel";
    config[6] = {
    id     : id,
    page: pagesList.pages[2].pageName,
    pageId: pagesList.pages[2].pageId,
    descr  :"Steel 2",
    widget : widget,
    topic: prefix + "/" + deviceId + "/" + widget + id,
    widgetConfig : {
    width  : "auto",
    height : 100,
    type   : "Linear",
    titleString: "Humidity 1",
    unitString : "% Hum",
    threshold: 90
}
};


// extract command and param
var msg2 = JSON.parse(msg.payload.toString());

if (msg2.command==="getPages")
    {
     msg.topic=prefix + "/" + deviceId + "/response";
     msg.payload=JSON.stringify(pagesList);
     node.send(msg);   
    }

else if (msg2.command === "getPageById" && msg2.param > 0) 
    {
                 pagesList.pages.forEach(function(item, i, arr) {
                // it is one of our pages?
                if (item.pageId === msg2.param) {
                    // node.warn('Request is for existing page "' + item.pageName + '", pageId="' + msg2.param + '"');
                    pubPage(msg2.param);
                }
            });
    }

else if (msg2.command === "getPageById" && msg2.param === 0) 
        {
            //node.warn('Request is for All pages.');
            pubPage(0);
        }






function pubPage(page) {

    // check all widgets and pub widgets config from requested page
    config.forEach(function(item, i, arr) {
        if (item.pageId === page || page === 0) {

            // pub config for one widget
            msg.topic=prefix + "/" + deviceId + "/config";
            msg.payload=JSON.stringify(item);
            node.send(msg);
            //node.warn("Page " + item.pageId + " id " + i);
            // pub status for one widget
            pubStatus(i);
        }
    });
}


function pubStatus(i) {
var status;
switch (i)
    {
        case 0 : status=global.get("IoTmanager_toggle0"); break;
        case 1 : status=global.get("IoTmanager_toggle1"); break;
        case 2 : status=global.get("IoTmanager_fillgauge2"); break;
        case 3 : status=global.get("IoTmanager_fillgauge3"); break;
        case 4 : status=global.get("IoTmanager_fillgauge4"); break;
        case 5 : status=global.get("IoTmanager_steel5"); break;
        case 6 : status=global.get("IoTmanager_steel6"); break;
        case 7 : status=global.get("IoTmanager_range7"); break;

    }
msg.topic=config[i].topic + "/status";
msg.payload=JSON.stringify({ status: status });
node.send(msg);
}

As for individual items - well, to turn on or off a switch is as easy as...

var fred=msg.payload;
msg.topic="/IoTmanager/bedrock/toggle0/status";
msg.payload="{\"status\":\""+fred+"\"}";
global.set("IoTmanager_toggle0",fred);
return msg;

Depending on whether you fire the string "0" or "1" at that function it will turn on or off the switch.

The main function above is comprised mainly of definitions for the various items and you can find out more about them at the author's site - indeed that IS the place to look in case he changes anything and expect him to add more in future.

So - do we have an up and coming competitor for Blynk and Imperihome? I'll leave that for you to decide.

Facebooktwittergoogle_pluspinterestlinkedin