Software Archive
Read-only legacy content
17061 Discussions

IoT dashboard Control/Actuator working code or tutorial?

David_B_6
Beginner
4,847 Views

Hi there,

I am new to all of this, but fairly technical, UNIX guy, some coding background but I am not a developer full time and am trying to learn Intel's Edison IoT.  I have a new Edison and an Arduino and am using the Arduino IDE and SSH to the device. When I started I re-flashed the Edison with the latest and set up an IoT Analytics account. I have the device registered with and and able to send to the analytics dashboard (https://dashboard.us.enableiot.com) and it works fine. I have sent a number of observations temp, humidity and a "seismograph" sensor I created. It all worked fine. I am also able to connect to the Arduino/Edison and read and activate a number of Grove sensors, etc. and it all works fine. I can turn lights on, flash them, read the sound, temp sensors, turn on the relay, etc. all fine.

What I am REALLY trying to do is control an LED from the Cloud. After reading all of the tutorials and getting this far I tried to run the Actuator example program and it didn't work. First it was syntax errors by I managed to correct those (conflicting libraries between the iotkit and arduino libraries. The code compiles fine and I am able to successfully send a command (LED On, value 1, component "powerswitch", command "LED.v1.0", value 1 and did this 5 times successfully tonight.

The problem is nothing happens on the board! No light, no message in the serial window, no message to the user, no error, nothing.

I read that you have to enable mgtt mode not REST so I did that but I'm at a loss. the sample code is complicated to me and I don;t udnerstand all parts of what it is doing. My specific questions are:

  • how can I view/see a log to even know if the Edison received the call from the cloud?
  • I know the agent is running on the device and can send commands directly from the terminal on my Mac and they work. 
  • In looking at the code it is unclear to me where the payload is coming in from the cloud server - I see some aJsonObject lines and assume that's them but have no idea what's supposed to be happening there and if it is

Here's the sample code that comes with the iotkit dist (I haven't edited it at all but would change "component" and command to match mine (powerswitch and LED.v1.0). (I am particularly curious about the iotkit.send("power", 1) - why would it be sending when the objective is to receive a 1 or 0 from the cloud??)

//This example reacts for default actuator component if registered on device
//LED.v1.0 command is used
//When executed from Control section on dashboard with value 0, LED light is turned off
//When executed from Control section on dashboard with value 1, LED light is turned on
//iotkit-agent must use MQTT connection (not REST) for actuation to work.
//It also sends 1 as power when agent is started.

#include <IoTkit.h>    // include IoTkit.h to use the Intel IoT Kit
#include <Ethernet.h>  // must be included to use IoTkit
#include <aJSON.h>
#include <stdio.h>

// create an object of the IoTkit class
IoTkit iotkit;        
int temp;
char buf[112];

void setup() {
  Serial.begin(115200);
  // call begin on the IoTkit object before calling any other methods
  iotkit.begin();
  delay(10500);
  iotkit.send("power", 1);
}

void loop() {
  iotkit.receive(callback);
  delay(5000);
}

void callback(char* json) {
  Serial.println(json);
  aJsonObject* parsed = aJson.parse(json);
  if (&parsed == NULL) {
    // invalid or empty JSON
    Serial.println("recieved invalid JSON");
    return;
  }
   
  aJsonObject* component = aJson.getObjectItem(parsed, "component");
  aJsonObject* command = aJson.getObjectItem(parsed, "command"); 
  aJsonObject* argv = aJson.getObjectItem(parsed, "argv");
  aJsonObject* argvArray = argv->child;
  aJsonObject* name = argvArray->child; // name : on
  aJsonObject* value = name->next; // value: 1/0
  
  if ((component != NULL)) {
    if (strcmp(component->valuestring, "actuator") == 0) {
      if ((command != NULL)) {
        if (strcmp(command->valuestring, "light") == 0 && strcmp(value->valuestring, "0") == 0) {
          Serial.println("Light Off!");
          pinMode(13, OUTPUT);
          digitalWrite(13, false);
        }
        if (strcmp(command->valuestring, "light") == 0 && strcmp(value->valuestring, "1") == 0) {
          Serial.println("Light on!");
          pinMode(13, OUTPUT);
          digitalWrite(13, true);
        }
      }
    }
  }
}

Thanks to anyone who can help - I am at a standstill at this point and appreciate any feedback that could get me sorted.

D.

 

0 Kudos
30 Replies
Brian_B_Intel
Employee
3,293 Views

Hi David.
You're almost there. The agent log is in /tmp/agent.log. I would tail this log as you run your actuation example sketch so you can see incoming/outgoing messages processed by the agent:
# tail -f /tmp/agent.log

One thing to note: if you register a new component on your device, you will need to restart the agent:
# systemctl restart iotkit-agent

You should see the following in the log as the actuation message comes in from the Cloud:

{
    "type": "command",
    "transport": "mqtt",
    "content": {
        "domainId": "c349d0ef-a076-413a-a447-xxxxxxxxx",
        "deviceId": "jasper-edison",
        "gatewayId": "jasper-edison",
        "componentId": "805110c5-8f82-4494-a0aa-xxxxxxxxx",
        "command": "LED.v1.0",
        "params": [{
            "name": "LED",
            "value": "1"
        }]

    },
    "level": "info",
    "message": "STATUS: device/jasper-edison/control",
    "timestamp": "2015-02-03T21:59:38.611Z"
}
{
    "level": "info",
    "message": "Fired STATUS: %sdevice/jasper-edison/control{\"type\":\"command\",\"transport\":\"mqtt\",\"content\":{\"domainId\":\"c349d0ef-a076-413a-a447-xxxxxxx\",\"deviceId\":\"jasper-edison\",\"gatewayId\":\"jasper-edison\",\"componentId\":\"805110c5-8f82-4494-a0aa-xxxxxxxx\",\"command\":\"LED.v1.0\",\"params\":[{\"name\":\"LED\",\"value\":\"1\"}]}}",
    "timestamp": "2015-02-03T21:59:38.614Z"
}

The "callback" function in the sketch is called every 5 seconds (by iotkit.receive) and will handle the actuation message being relayed by the client. The function then parses the message to look for the "LED" parameter value. It will set board pin 13 to that value (0 or 1)..

Brian

0 Kudos
Brian_B_Intel
Employee
3,293 Views

Aside from the other actuation samples for Python and Node.js, there is some further information in the agent wiki in GitHub.

Samples repo:
Python
Node.js

Good luck and let me know how it goes.
Brian

0 Kudos
David_B_6
Beginner
3,293 Views

Thanks very much for replying Brian - very much appreciated. I'm completely stuck.

I assume when you say the log is /tmp/agent.log you mean /tmp on the Edison/Arduino, not on my Mac, correct? I logged in to the Edison via Serial as root. I went cd /tmp and ls and I see no agent.log. I looked at what was there and this is what I see. the files in /tmp are bolded below:

             Poky (Yocto Project Reference Distro) 1.6 Interactio_Hub ttyMFD2
 
             Interactio_Hub login: root
             Password: 
             [   30.987805] systemd-fsck[262]: /dev/mmcblk0p10: recovering journal
             [   31.048046] systemd-fsck[262]: /dev/mmcblk0p10 contains a file system with errors, check forced.
             [   31.174725] systemd-fsck[262]: /dev/mmcblk0p10: 17/152608 files (0.0% non-contiguous), 26872/610299 blocks
             root@Interactio_Hub:~#                   
            root@Interactio_Hub:~# 
            root@Interactio_Hub:~# cd /tmp
            root@Interactio_Hub:/tmp# ls
            log.txt
            log_er.txt
            systemd-private-1639e800f5cc41d69c807e406f8ffd21-systemd-timesyncd.service-GEit4F
            watchdog-sample.tmp

            wpa_ctrl_235-1

 
Perhaps I have to turn logging on? I don't even know how nor have I been able to find any complete documentation for iotkit...

Also, I tried "tailing" agent.log as you suggested:

  1. what is "tailing"
  2. when I did it I sent a package from the dashboard which it said was sent but nothing happened or changed on my end and it took over my serial screen and I had to reboot the Arduino to get it back.

Last question - I am not sure that i have the syntax correct in the sketch. I have a component (the default actually) called "powerswitch" (all lower case). It is registered and seems OK both in the dashboard and by iotkit on the device. As I say I am able to send to it. It says it's Command String is "LED.v1.0". I have edited this is the sketch to change thew word component to powerswitch and command to LED.v1.0. Do I need to change any of the others? For instance, I also see:

  • power (in iotkit.send("power", 1);
  • an integer variable called "temp" which doesn;t appear to be referenced anywhere - is it leftover or ??
  • argv - not sure what this is
  • then in the IF statements there are "actuator" and "light"
  • last, in the IF statements there are pinmode commands to send the high or low bit, but they both say pinmode(13, OUTPUT); - do I need to change OUTPUT to 1 and 0 respectively??

Since it's supposed to be a beginner example I was hoping there would be some clear documentation describing line by line what it's doing and what the variables are...

I'm sorry, I'm not a developer and am just trying to turn a light on/off from the Cloud for a prototype I am building. Very frustrating!

Thanks again,

David

 

 

0 Kudos
David_B_6
Beginner
3,293 Views

Quick update - I was able to vi agent.log. Is it hidden?? Here is what I see:

{"level":"info","message":"Trying to connect to host ...","timestamp":"2015-02-0
{"level":"info","message":"Starting Health testing ","timestamp":"2015-02-03T23:
{"level":"info","message":"Trying with Secure Connection tobroker.us.enableiot.c
{"level":"info","message":"Waiting for MQTTConnector to connect # 1","timestamp"
{"level":"info","message":"MQTTConnector: Connection successful to broker.us.ena
{"kind":"healthcheck","isHealthy":true,"currentSetting":"PROD","name":"iotkit-ga
{"level":"info","message":"Connected to broker.us.enableiot.com","timestamp":"20
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
- /tmp/agent.log 1/7 14%
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

0 Kudos
David_B_6
Beginner
3,293 Views

Update later tonight.

I have spent hours going through the actuator code and here is what I have now. Note: I am just trying to see the json payload in the serial terminal at this point, so all I am doing is running the code, printing "online" in the serial window and turning the LED on. My intent here is to try to understand the sequence of the code. Ideally I would step through the code or even better, echo each line as it executes so i could see where it is failing. No printlns appear other than online when i execute the code below.

So, I have narrowed my question/confusion down somewhat - I don't think the callback procedure is running at all, as I am getting no "SerialPrintln"s at all even though I added some to "echo" the code execution. My question at this point is where should the callback procedure be in the code (in the loop or not? I suspect not because it is defining the procedure).

This brings me to my next question - what calls the callback procedure and also the aJsonObject* calls?

#include <IoTkit.h>    // include IoTkit.h to use the Intel IoT Kit
#include <Ethernet.h>  // must be included to use IoTkit
#include <aJSON.h>
#include <stdio.h>

// create an object of the IoTkit class
IoTkit iotkit;        
//int temp;
int led = 8;
char buf[112];

void setup() {
  Serial.begin(115200);
  // call begin on the IoTkit object before calling any other methods
  iotkit.begin();
  delay(3000);
  Serial.println("online");
  iotkit.send("power", 1);
  pinMode(led, OUTPUT);
  digitalWrite(led, 1);        // turn the LED on (HIGH is the voltage level)
}

void loop() {
  iotkit.receive(callback);    // wait for payload from Cloud via JSon
  delay(2000);                 // the loop routine runs over and over again forever:
}

void callback(char* json) {
  Serial.println(json);
  aJsonObject* parsed = aJson.parse(json);
  Serial.println("test callback is running?");
  if (&parsed == NULL) {
    // invalid or empty JSON
    Serial.println("recieved invalid JSON");
    return;
  }
   
  aJsonObject* component = aJson.getObjectItem(parsed, "powerswitch");
  Serial.println("powerswitch");
  aJsonObject* command = aJson.getObjectItem(parsed, "LED.v1.0"); 
  Serial.println("LED.v1.0");
  aJsonObject* argv = aJson.getObjectItem(parsed, "argv");
  Serial.println("argv");
  aJsonObject* argvArray = argv->child;
  aJsonObject* name = argvArray->child; // name : on
  aJsonObject* value = name->next; // value: 1/0
  

//  if ((component != NULL)) {
//    if (strcmp(component->valuestring, "actuator") == 0) {
//      if ((command != NULL)) {
//        if (strcmp(command->valuestring, "light") == 0 && strcmp(value->valuestring, "0") == 0) {
//          Serial.println("Light Off!");
//          pinMode(led, OUTPUT);
//          digitalWrite(led, 0);
//        }
//        if (strcmp(command->valuestring, "light") == 0 && strcmp(value->valuestring, "1") == 0) {
//          Serial.println("Light on!");
//          pinMode(led, OUTPUT);
//          digitalWrite(led, 1);
//        }
//      }
//    }
// }

}

Last, I checked to make sure iotkit-agent is running. It is, but I noticed an intermittent issue where when executing some agent commands I get a bad username/password error:

root@Interactio_Hub:~# iotkit-agent catalog
2015-02-04T05:52:01.063Z - info: Trying to disconnect 
2015-02-04T05:52:01.092Z - info: Sending attributes...
2015-02-04T05:52:01.101Z - info: Trying with Secure Connection tobroker.us.enableiot.com:8883
2015-02-04T05:52:01.143Z - info: Waiting for MQTTConnector to connect # 1
2015-02-04T05:52:02.018Z - error: UncaughtException: Connection refused: Bad username or password
2015-02-04T05:52:02.044Z - error: Error: Connection refused: Bad username or password

    at MqttClient._handleConnack (/usr/lib/node_modules/iotkit-agent/node_modules/mqtt/lib/client.js:508:9)
    at Connection.<anonymous> (/usr/lib/node_modules/iotkit-agent/node_modules/mqtt/lib/client.js:191:10)
    at Connection.EventEmitter.emit (events.js:95:17)
    at Connection._write (/usr/lib/node_modules/iotkit-agent/node_modules/mqtt/lib/connection.js:187:12)
    at doWrite (_stream_writable.js:226:10)
    at writeOrBuffer (_stream_writable.js:216:5)
    at Connection.Writable.write (_stream_writable.js:183:11)
    at write (_stream_readable.js:582:24)
    at flow (_stream_readable.js:591:7)
    at CleartextStream.pipeOnReadable (_stream_readable.js:623:5)

I Googled this but can't find anything useful. Does uname and pwd get defined anywhere?? I am assuming this is username and pwd for dashboard.us.enableiot.com?

Thanks again in advance - any help is appreciated.

David

0 Kudos
Brian_B_Intel
Employee
3,293 Views

Thanks for your patience. You're doing all the right things from a debugging perspective. From the log, it looks like your agent is running fine. Can you check which version of the agent you have? In the Edison console window run:
# iotkit-admin -V

If it's older than 1.5.1 then actuation is broken and you will need to update the agent. The agent isn't able to understand actuation messages before that version. Also, there was a server upgrade yesterday so I need to check on the errors you are seeing in the log. You shouldn't need to worry about any usernames or passwords.

Regarding your questions on the sketch. The sketch uses a component named "power". Here's a summary of what happens during the sketch:

Runs once at start:
void setup() {
  Serial.begin(115200);
 // this initializes the serial console 
  // call begin on the IoTkit object before calling any other methods
  iotkit.begin();  // this opens UDP ports 41234 for sending and 41235 for listening
  delay(10500);  // wait 10.5sec
  iotkit.send("power", 1);  // send a test observation to the Cloud for component "power" (value=1). You should see this in the agent log
}

Runs continuously:
void loop() {
  iotkit.receive(callback);
// listens to UDP port 41235 for actuation messages and calls "callback" if one is received
  delay(5000);  // wait 5sec
}

For the logic in "callback" that toggles the LED, 
pinMode(13, OUTPUT);  // sets pin-13 for writing (output)
digitalWrite(13, false/true);  // sets pin-13 to on/off (1 or 0)

The rest of the "callback" sketch is mainly parsing the JSON data structure that the agent is sending. It's pretty messy in C so the code looks ugly. The message format from the agent looks like:

{
    "component": "power",
    "command": "LED.v1.0",
    "argv": [{
        "name": "LED",
        "value": "1"
    }]
}

The important parts of the message are "component", "name" and "value". "Power" should be the name of your component. It should only have one parameter - "LED". These are the parameters you set on the web page when you submitted the actuation request.

Also, "tail" is a Linux command that lists the last few lines of a file. It's useful (with the '-f' option) to continuously display the end of a log file. I'll run the command on my Edison in my console terminal and i'll see the agent activity as my sketches run. (hit control-C to exit tail)
# tail -f /tmp/agent.log

Brian

0 Kudos
David_B_6
Beginner
3,293 Views

Awesome information - thanks a million.

I checked the version and I have 1.5.0. Oddly, I downloaded this Feb 2nd and re-flashed the Edison so one would assume it was up to date, but apparently not. I'm thinking it would be a good idea for Intel to update the dist. that links from the iot downloads page.

I'll start by doing the update with npm as outlined on the wiki - hopefully it works. it says it's installing version 1.6.4. I'm really surprised that the default I had was 1.5.0 given I installed in Monday...

Once (if) I get that done I'll try to re-register the device as "power" not "powerswitch" and go from there. When you say the one parameter is LED does that mean i can drop the v1.0 off LED.v1.0?

Thanks Brian - you're a life saver.

David

 

 

0 Kudos
David_B_6
Beginner
3,293 Views

I really don;t know what to do with this thing at this point (let's just say a hammer is looking pretty good at this point!)

I try to update iotkit-agent. I can't find any clear instructions, so I follow this:

2.3.2. Agent is not pre-installed

If you are working on a device other than a Galileo or Edison, or the agent is not pre-installed: 

You may need to install Node.js and npm first. Please see the Node.js web site for instructions. 

You will need to install the agent and it’s dependencies. To do that, “cd” to the directory where you want the agent installed and type:

      npm install iotkit-agent

      mv node_modules/iotkit-agent/ .

      rm –rf node_modules

First command - success!

Second command (mv command) - fails. Says I cannot modify it since it is not a directory. This is Intel documentation about Intel code on an Intel board - this should just work; someone needs to check this stuff for errors and edit it, geez.

I decided to skip it and restart the Edison. I do so (twice) and get this: 

root@Interactio_Hub:/usr/bin# iotkit-admin test
2015-02-04T22:49:34.887Z - info: Trying to connect to host ...
2015-02-04T22:49:34.915Z - info: Starting Health testing 
2015-02-04T22:49:34.923Z - info: Trying with Secure Connection tobroker.us.enableiot.com:8883
2015-02-04T22:49:34.974Z - info: Waiting for MQTTConnector to connect # 1
2015-02-04T22:49:36.479Z - info: MQTTConnector: Connection successful to broker.us.enableiot.com:8883
2015-02-04T22:49:36.677Z - info: STATUS: device/e6-2b-c2-c2-86-7e/health kind=healthcheck, isHealthy=true, currentSetting=PROD, name=iotkit-gateway, build=0.12.
0, date=2015-01-26T13:46:41.332Z, items=[connected=true]
2015-02-04T22:49:36.685Z - info: Fired STATUS: %sdevice/e6-2b-c2-c2-86-7e/health{"kind":"healthcheck","isHealthy":true,"currentSetting":"PROD","name":"iotkit-ga
teway","build":"0.12.0","date":"2015-01-26T13:46:41.332Z","items":[{"broker":{"connected":true}}]}
2015-02-04T22:49:36.692Z - info: Connected to broker.us.enableiot.com
2015-02-04T22:49:36.694Z - info: Environment: PROD
2015-02-04T22:49:36.695Z - info: Build: 0.12.0
root@Interactio_Hub:/usr/bin# iotkit-agent -V
2015-02-04T22:49:50.596Z - info: Trying to disconnect 
2015-02-04T22:49:50.631Z - info: Sending attributes...
2015-02-04T22:49:50.640Z - info: Trying with Secure Connection tobroker.us.enableiot.com:8883
2015-02-04T22:49:50.692Z - info: Waiting for MQTTConnector to connect # 1
2015-02-04T22:49:50.915Z - error: UncaughtException: Connection refused: Bad username or password
2015-02-04T22:49:50.945Z - error: Error: Connection refused: Bad username or password

    at MqttClient._handleConnack (/usr/lib/node_modules/iotkit-agent/node_modules/mqtt/lib/client.js:508:9)
    at Connection.<anonymous> (/usr/lib/node_modules/iotkit-agent/node_modules/mqtt/lib/client.js:191:10)
    at Connection.EventEmitter.emit (events.js:95:17)
    at Connection._write (/usr/lib/node_modules/iotkit-agent/node_modules/mqtt/lib/connection.js:187:12)
    at doWrite (_stream_writable.js:226:10)
    at writeOrBuffer (_stream_writable.js:216:5)
    at Connection.Writable.write (_stream_writable.js:183:11)
    at write (_stream_readable.js:582:24)
    at flow (_stream_readable.js:591:7)
    at CleartextStream.pipeOnReadable (_stream_readable.js:623:5)
root@Interactio_Hub:/usr/bin# 

The agent will not start, athough the iotkit-admin test worlks successfully., 

Now I can't even run iotkit-agent -V to see what version it is.

Is it just me or ???

Thanks...

0 Kudos
David_B_6
Beginner
3,293 Views

OK, thanks to several messages and help from Brian I managed to get it working but it was a host of problems:

First - the iotkit version on the Edison was too old. I downloaded and flashed the latest Edison image (Rel-1-Maint-WW42 from https://communities.intel.com/docs/DOC-23242) on Monday but evidently they include a very old iotkit in that dist (1.5.0). Actuation will not work with anything below 1.5.1.  you can see what version you have by typing:

iotkit.admin - V

To upgrade it, once you have the Edison flashed and connected to the internet, run the following command (from Brian):

npm update -g iotkit-agent

The latest I installed today was 1.6.4

Second - the example code included in the iotkit dist is horribly wrong. Here are the details as I sent them to Brian tonight at 11:46pm Pacific time (I hope this helps someone else):

Here is what I see in my serial monitor. this is the JSON payload from the IoT Analytics Dashboard (plus some printlns I echoed to see what was happening): 

Good JSON Command from Server: {"component":"power","command":"LED.v1.0","argv":[{"name":"LED","value":"1"}]}
{"component":"power","command":"LED.v1.0","argv":[{"name":"LED","value":"1"}]}
OK just finished aJsonObject lines
begin loop after comp null line
continue, now after strcmp power in loop
continue, now after command null in loop
Light on!
Good JSON Command from Server: {"component":"power","command":"LED.v1.0","argv":[{"name":"LED","value":"0"}]}
{"component":"power","command":"LED.v1.0","argv":[{"name":"LED","value":"0"}]}
OK just finished aJsonObject lines
begin loop after comp null line
continue, now after strcmp power in loop
continue, now after command null in loop
continue, now after strcmp command LED line in loop
Light Off!

and here is the code I am running:

#include <IoTkit.h>    // include IoTkit.h to use the Intel IoT Kit
#include <Ethernet.h>  // must be included to use IoTkit
#include <aJSON.h>
#include <stdio.h>

// create an object of the IoTkit class
IoTkit iotkit;        
int temp;
//int LED;
char buf[112];

void setup() {
  Serial.begin(115200);
  // call begin on the IoTkit object before calling any other methods
  iotkit.begin();
  delay(10500);
  iotkit.send("power", 1);
}

void loop() {
  iotkit.receive(callback);
  delay(5000);
}

void callback(char* json) {
  Serial.println(json);
  aJsonObject* parsed = aJson.parse(json);
  if (&parsed == NULL) {
    // invalid or empty JSON
    Serial.println("recieved invalid JSON");
    return;
  }

aJsonObject* component = aJson.getObjectItem(parsed, "power");
  aJsonObject* command = aJson.getObjectItem(parsed, "LED.v1.0"); 
  aJsonObject* argv = aJson.getObjectItem(parsed, "argv");
  aJsonObject* argvArray = argv->child;
  aJsonObject* name = argvArray->child; // name : on
  aJsonObject* value = name->next; // value: 1/0
  Serial.println("OK just finished aJsonObject lines");
  
//  if ((component != NULL)) {       // was stopping here
    Serial.println("begin loop after comp null line");
//    if (strcmp(component->valuestring, "power") == 0) {    //changed to power from actuator
//      strcmp(component->valuestring, "power");              //changed to power from actuator
        Serial.println("continue, now after strcmp power in loop");
//      if ((command != NULL)) {
        Serial.println("continue, now after command null in loop");
//      if (strcmp(command->valuestring, "LED.v1.0") == 0 && strcmp(value->valuestring, "0") == 0) { //changed to LED.v1.0 from light
        if (strcmp(value->valuestring, "1")) { //changed to LED.v1.0 from light
          Serial.println("continue, now after strcmp command LED line in loop");
          Serial.println("Light Off!");
          pinMode(13, OUTPUT);
          digitalWrite(13, 0); //should false be changed to 0?
        }
//      if (strcmp(command->valuestring, "LED") == 0 && strcmp(value->valuestring, "1") == 0) {
        if (strcmp(value->valuestring, "0")) {
          Serial.println("Light on!");
          pinMode(13, OUTPUT);
          digitalWrite(13, 1);
        }
//      }
//    }
//  }
}

I learned a few things and still have some questions. I will post this in the forum so it may help others.

1. Some of the syntax in the example code is wrong, especially for the default dashboard component powerswitch.

    The following need to be changed:

  • component needs to be changed to power
  • command needs to be changed to LED.v1.0
  • actuator needs to be changed to power
  • light needs to be changed to LED.v1.0

    This means the component on the Edison needs to be registered as “power” also, like this:

 iotkit-admin register power powerswitch.v1.0

2. The 4 nested IF statements are what was stopping the program from running past the aJsonObject parsing. In reviewing the code I added a series of printlns to debug where it was getting stuck. I determined that there are essentially 4 IFs: 2 are checking to see that the values received for control and command are not null and the other 2 are trying to be generic to scan any payload and match the conditions for component, command and arguments in the IF statement. It is trying to say:

  • IF the payload component is not NULL and
  • IF the payload component value is “power” then
  • IF the payload command value is “LED.V1.0” and
  • IF the payload command value is not null and
  • IF the payload argv value is “0”…
  • THEN turn the LED off

or

  • IF the payload command value is “LED.V1.0” and
  • IF the payload command value is not null and
  • IF the payload argv value is “0”…
  • THEN turn the LED on

The problem is this is a large combination of conditions in a series of nested IF statements and for whatever reason(s) the conditions don’t get met by the default dashboard payload so it does not execute.

In short, the logic just doesn’t work!

3. I did get it working, however the LED switches the wrong way! Note that in my code I had to change the bolded 0 in the code below to reverse it:

        if (strcmp(value->valuestring, " ")) {
          Serial.println("Light on!");
          pinMode(13, OUTPUT);
          digitalWrite(13, 1);

Now, I did make a lot of changes in the IF statements and perhaps something is amiss.

So! My question is:

Can anyone post some sample code (actually ideally working code, not just sample code…) to replace the conditions in the example’s nested IF statements? The conditions are needed for a production application; the way it is I can only control one component at a time.

David

0 Kudos
Matthias_H_Intel
Employee
3,293 Views

David B. wrote:

[...]

First - the iotkit version on the Edison was too old. I downloaded and flashed the latest Edison image (ww36-14) on Monday but evidently they include a very old iotkit in that dist (1.5.0). 

[...]

The latest Edison image should be ww42 I'd say. Nevertheless, the iotkit-agent there would still be fairly old - on my image it tells 0.8.7. Looks like I should upgrade iotkit-agent some time ...

0 Kudos
David_B_6
Beginner
3,293 Views

Hi Mathias - yes, you are correct. Sorry, I made a typo. The version I downloaded was:

Rel-1-Maint-WW42

From here:

https://communities.intel.com/docs/DOC-23242

Thanks, and yes, it looks like you should update it!

David

0 Kudos
Brian_B_Intel
Employee
3,293 Views

Great to hear. Yes, I think the main issue was the parameter name, “light”. I should have had you verify you had the latest sample code:

https://github.com/enableiot/iotkit-samples/blob/master/arduino/IoTkit/examples/IoTKitActuationExample/IotKitActuationExample.ino

This latest version has cleaner logic but could still be improved. The if/then logic is to verify that a received actuation message is actually for the component you are about to turn on/off. After parsing this message, the only things you really care about are:

component
argv: name
argv: value

Command really isn’t important. It’s an arbitrary string that is a property of the component’s type (i.e., powerswitch.v1.0).

The reason argv is an array is that a component-type can have several parameters. For example, you could have a motor which has multiple parameters:

onOff: 0/1 (or speed=0 could be 'off')
speed: 0-100  
direction: 0/1

Then, the sketch would extract all of these parameters from the message and if all values were present, set the appropriate pins.

Brian

0 Kudos
Jakub_C_
Beginner
3,293 Views

Guys,

I also can't get this thing running, I flashed clean my edison and updated iotkit to 1.6.4

I cannot switch it to mqtt:

iotkit-admin protocol mqtt

fs.js:427
  return binding.open(pathModule._makeLong(path), stringToFlags(flags), mode);
                 ^
Error: ENOENT, no such file or directory '/home/root/data/user.js'
    at Object.fs.openSync (fs.js:427:18)
    at Object.fs.readFileSync (fs.js:284:15)
    at Object.module.exports.saveToUserConfig (/usr/lib/node_modules/iotkit-agent/lib/common.js:236:23)
    at Command.<anonymous> (/usr/lib/node_modules/iotkit-agent/admin/configurator.js:225:28)
    at Command.<anonymous> (/usr/lib/node_modules/iotkit-agent/lib/commander/index.js:253:8)
    at Command.EventEmitter.emit (events.js:98:17)
    at Command.parseArgs (/usr/lib/node_modules/iotkit-agent/lib/commander/index.js:482:12)
    at Command.parse (/usr/lib/node_modules/iotkit-agent/lib/commander/index.js:374:21)
    at Object.<anonymous> (/usr/lib/node_modules/iotkit-agent/bin/admin.js:91:11)
    at Module._compile (module.js:456:26)

Please help!

0 Kudos
Brian_B_Intel
Employee
3,293 Views

Hi Jakub.

That looks like a bug in the agent but I need to verify. There are a couple of work-arounds.

1. You can move to the /usr/lib/node_modules/iotkit-agent and run the command.

2. Move the agent data directory to some non-default location. This is recommended in the update/install instructions as updating the agent will wipe out everything.
# iotkit-admin move-data-directory ~/.data
Then try setting MQTT protocol
# iotkit-admin protocol mqtt

Brian 

0 Kudos
David_B_6
Beginner
3,293 Views

Hi Jakub - sorry. I was away from my computer until now.

I forgot to mention that I also had this problem after upgrading to 1.6.4 - it must be a bug. I was able to work around it by setting "mqtt" manually in the config file. What iI did was:

1. change directories to /usr/lib/node_modules/iotkit-agent/config:

        cd /usr/lib/node_modules/iotkit-agent/config

2. edit the file with vi like this:

       vi global.json

edit the bolded line below and change REST to mqtt:

{
    "data_directory": "./data/",
    "listeners": {
        "mqtt_port": 1884,
        "rest_port": 9090,
        "udp_port": 41234,
        "tcp_port": 7070
    },
    "receivers": {
        "udp_port": 41235,
        "udp_address": "0.0.0.0"
    },
    "logger": {
        "LEVEL": "info",
        "PATH": "/tmp/"
    },
    "default_connector": "mqtt",
    "connector": {
        "mqtt": {
            "host": "broker.us.enableiot.com",
            "port": 8883,
            "qos": 1,
            "retain": false,

If you don;t know vi, you can follow this guide:

           http://www.cs.colostate.edu/helpdocs/vi.html

If you need help let me know.

Good luck!

David

0 Kudos
Joanna_R_Intel
Employee
3,293 Views

Hi Jakub and David,

Jakub - Can you please check what's the data directory in global.conf? Did you follow upgrade instructions from https://github.com/enableiot/iotkit-agent? It looks like you didn't perform "move-data-directory" action. Please run:

./iotkit-admin.js set-data-directory <directory where device.json and user.js are stored>

To check where you can find device.json, you can run:

find / -name device.json

 

David - you should not edit global.conf. This config is meant to be overridden by updates, such changes should be done in data/user.js.

Regards

0 Kudos
David_B_6
Beginner
3,293 Views

Thanks Joanna - that would be great except the command I was given (see above and copied here) does not work:

      npm install iotkit-agent 

      mv node_modules/iotkit-agent/ . 

      rm –rf node_modules

when I execute the move command it fails. Can you please test it on an Edison and post the command that works??

thanks!

David

 

0 Kudos
Jakub_C_
Beginner
3,293 Views

Thx guys... I managed to fix that...

I was messing around trying to run this piece of example code then I broke something and:

1. reflashed edison

2. Updated iotkit using command npm update -g iotkit-agent

3. hit myself in the head - I must change protocol to mqtt, trying to do so I encountered problem above and posted it here.

4. read your advice and what finally helped?

mv node_modules/iotkit-agent ./
cd iotkit-agent
npm install forever

Ok, mqtt successfully set... let me try if it works now...

nope...

is it normal I cannot download catalog while using mqtt?

iotkit-admin catalog
2015-02-06T19:34:16.511Z - info: Getting Component Getting
2015-02-06T19:34:16.540Z - info: Trying with Secure Connection tobroker.us.enableiot.com:8883
2015-02-06T19:34:16.587Z - info: Waiting for MQTTConnector to connect # 1
2015-02-06T19:34:18.528Z - info: MQTTConnector: Connection successful to broker.us.enableiot.com:8883

and it stucks there...

edison appears active on dashboard but I cannot see incoming mqtt when I send command from dashboard while running:

tail -f /tmp/agent.log

0 Kudos
David_B_6
Beginner
3,293 Views

Hi Jakub,

I have the same issue with it failing when I try to run the catalog (good, it's not just me). Again, I suspect it's a big because it's not just me and this stuff seems very buggy/unprepared for production (the commands in the docs don;t work, the "latest" flash dist has a really old version of iotkit and nowhere does it tell you to upgrade it or how, etc. etc. etc.)

Even though the catalog doesn't work for me the actuator code does. What I'd suggest is you copy the exact code I am running on 1.6.4 which works. I have attached the whole file here (I had to rename it from .ino to .txt. Save it on your system and rename it back to .ino and it should run for you, assuming you are using the default "Powerswitch.v1.0" in the IoT Analytics Dashboard. You should not need to change anything on the IoT Dashboard site.

Good luck.

David

0 Kudos
Jakub_C_
Beginner
3,199 Views

Tried running your code(i use powerswitch, not power, so i renamed only that part) but my edison seems not receiving commands from dashboard, cannot see any command incoming tailing agent.log.

When I upload your code led only blinks once, nothing appears on tail nor in arduino serial monitor... when sending commands...

 

0 Kudos
Reply