Linux Agent

This guide helps you experiment with the Ayla Linux Device Solution on a Raspberry Pi. In this particular edge solution, the Ayla Agent is named devd and the Ayla Example App is named appd. Both are implemented as background processes. The video explains more:

You can connect a Raspberry Pi to the Ayla Public Account or, if it exists, to your company's Ayla Customer Account. For the former, you need to obtain a devd.conf file from Ayla. See Set up your account.

Connect the device

Create a template

Browse to the Ayla Developer Portal, and create a template with the following details.

Visibility:private
Name:Linux v1.7
Description:Linux v1.7
Registration:Dsn
Model:linuxevb
Version:linux-v1.7
Type:Wifi

After creating the template, copy & paste the following properties into a text file, and import the file.

base_type,direction,name,scope
boolean,input,batch_hold,user
boolean,output,Blue_button,user
boolean,input,Blue_LED,user
string,input,cmd,user
decimal,input,decimal_in,user
decimal,output,decimal_out,user
file,input,file_down,user
file,output,file_up,user
boolean,input,file_up_test,user
boolean,input,Green_LED,user
integer,input,input,user
message,input,large_msg_down,user
message,output,large_msg_up,user
string,input,large_msg_up_test,user
string,output,log,user
integer,output,output,user
string,output,version,user

Finally, click the new version property, check Host SW Version, and click OK.

Set up a Raspberry Pi

  1. Obtain a Raspberry Pi. We used a Raspberry Pi 3 Model B+.

  2. Download Raspbian Lite. Do not unzip. We used raspbian_lite-2018-04-19.

  3. Download Etcher to your computer, and install it.

  4. Insert the MicroSD card into a card reader, and insert the reader into a USB port on your computer:



  5. Run Etcher, and flash the Raspian image onto the MicroSD card.

  6. In a terminal, access the boot directory (e.g. cd /Volumes/boot or cd /media/matt/boot).

  7. Enable serial communication by appending enable_uart=1 to config.txt.

  8. Enable Secure Shell by creating an empty ssh text file with touch ssh.

  9. Enable Wi-Fi by creating a wpa_supplicant.conf file with content similar to the following:

    ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
    update_config=1
    country=US
    network={
        ssid="network"
        psk="password"
        key_mgmt=WPA-PSK
    }
    

    At boot time, Raspian copies this file to /etc/wpa_supplicant/wpa_supplicant.conf.

  10. Unmount the card, remove it from the reader, insert it into the RPi (upside down), and power on.

  11. Secure Shell to the RPi (or, optionally, use a serial/console cable):

    1. Determine the RPi IP address. You can browse to the router manager page, or run arp -a in a shell.

    2. Run ssh [email protected]. Normally, you will see a message similar to the following:

      The authenticity of host '192.168.1.9 (192.168.1.9)' can't be established.
      ECDSA key fingerprint is SHA256:CcQtTqvRl5SLlAbCdEfG/UsK0/NN018UKnSRw.
      Are you sure you want to continue connecting (yes/no)?
      

      Sometimes, however, you will see this message:

      @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
      @    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
      @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
      IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
      Someone could be eavesdropping on you right now (man-in-the-middle attack)!
      It is also possible that a host key has just been changed.
      The fingerprint for the ECDSA key sent by the remote host is
      SHA256:r4Y+vxKp5N6tEsMJtc6za1v/Rujms4wfjMY51jH8wsw.
      Please contact your system administrator.
      Add correct host key in /Users/matt/.ssh/known_hosts to get rid of this message.
      Offending ECDSA key in /Users/matt/.ssh/known_hosts:5
      ECDSA host key for 192.168.1.8 has changed and you have requested strict checking.
      Host key verification failed.
      

      To solve this, open ~/.ssh/known_hosts on your computer, delete the offending row (e.g. 5), save, and re-run ssh.

    3. Type yes, and enter raspberry for password. (Your username is pi).

  12. Determine whether git is installed. If not, install:

    $ git --version
    $ sudo apt-get update
    $ sudo apt-get install git -y
    
  13. Determine whether wiringpi is installed. If not, install:

    $ gpio -v
    $ sudo apt-get install wiringpi
    

Install Ayla

Clone the Ayla repository

  1. In the secure shell, ensure that you are in your home directory (e.g. /home/pi).
  2. Clone the Ayla device-linux-public repository. You will be asked for your Github username and password.

    $ git clone https://github.com/AylaNetworks/device_linux_public.git
    
  3. View the release history, and, if the latest release is not adc-1.7, get adc-1.7:

    $ cd device_linux_public
    $ git log
    $ git checkout 5a4c0760b379a4c3cbbc698252d24e2b1286b51b
    

Edit ayla_install.sh

  1. Copy ayla_install.sh to your home directory:

    $ cd ~
    $ cp ~/device_linux_public/dev_kit/raspberry_pi/ayla_install.sh .
    
  2. Open the file for editing, and set ayla_src_dir:

    ayla_src_dir="/home/pi/device_linux_public"
    
  3. Search for install_ayla_modules, comment out the following code in the function, and save.

    # if echo "$ayla_package" | grep -q "\.tar$" || echo "$ayla_package" | grep -q "\.tar.gz$" || echo 
    "$ayla_package" | grep -q "\.tgz$"; then
    #   install_tar "$ayla_package_path" "$ayla_src_dir"
    # elif echo "$ayla_package" | grep -q "\.git$"; then
    #   git_clone_repo "$ayla_package" "$ayla_src_dir"
    # else
    #   error_exit "unsupported package type: $ayla_package_path"
    # fi
    

Edit appd.c

  1. Open device_linux_public/app/appd/appd.c.
  2. Search for appd_template_version.
  3. Replace the current value with linux-v1.7 to enable appd to identify your template.
  4. Save the file.

Install the Ayla Edge Solution

  1. Create a dummy devd.conf file required by ayla_install.sh:

    $ touch devd.conf
  2. View installation options:

    $ ./ayla_install.sh -h
  3. Start the installation. Wireless is the default mode. Wireless requires the -z flag.

    $ sudo ./ayla_install.sh -z
    
    • Include -z to install BLE support.
    • Include -n to specify Ethernet (not Wi-Fi).
    • Include -u to install over a previous installation.
  4. When the installation completes, do NOT reboot yet.

Configure your device

Important: In order for an RPi to connect to the Ayla Cloud, it needs a valid devd.conf file in ~/ayla/config/. If you obtained one from Ayla, copy it from your computer to your RPi (e.g. scp devd.conf [email protected]:). Then, skip to Step 7 below. Otherwise, complete the following steps to create one.

1. Create a dsn.xml file

  1. Browse to the Ayla Dashboard Portal, and log in.
  2. Click Factory Actions in the sidebar.
  3. Click the Reserve DSNs button.
  4. For Model, select AY001MRT1-Linux Software Agent.
  5. In the textbox on the right, select 1.
  6. Click Submit. Ayla reserves for you a unique Device Serial Number (DSN) (e.g. AC000W123456789).
  7. Download the archive file to your computer.
  8. Unzip the archive file to extract the XML file.
  9. Secure Copy the XML file from your computer to /home/pi on your RPi:

    $ scp AC000W123456789.xml [email protected]:
    

2. Create on oem_info file

  1. On your computer, create a text file called oem_info.
  2. Copy and paste the content below. Each line is a space-delimited, key:value pair with no quotes.

    region myRegion
    oem myOemId
    oem_model myOemModel
    oem_secret myOemSecret
    mfg_model myMfgModel
    mfg_serial myMfgSN
    mfg_sw_version v1.2.3_A
    odm myOdmName
    
  3. Replace myRegion with US, EU, or CN.
  4. Replace myOemId with your oemId (see Ayla Dashboard Portal > OEM Profile > OEM ID).
  5. Replace myOemModel with the linuxevb.
  6. Replace myOemSecret with your oemSecret (see Ayla Dashboard Portal > OEM Profile > OEM Secret)
  7. Leave the other values alone, and save.
  8. Secure Copy the file to /home/pi on your RPi:

    $ scp oem_info [email protected]:
    

3. Make the config_gen utility

  1. On your RPi, change directory to your Ayla source directory:

    $ cd ~/device_linux_public
    
  2. Build config_gen.

    $ sudo make host_utils
    
    The newly built utility is in ~/device_linux_public/build/native/utils.

4. Run config_gen

  1. View command-line options:

    $ cd ~
    $ ./device_linux_public/build/native/utils/config_gen
    
  2. Run config_gen to generate a .conf file:

    $ ./device_linux_public/build/native/utils/config_gen -n -d ./AC000W123456789.xml -i ./oem_info
    

5. Rename the file

Rename the resulting AC000W123456789.conf file to devd.conf (overwriting any existing devd.conf file):

$ mv AC000W123456789.conf devd.conf

6. Modify devd.conf

  1. Open devd.conf for editing.
  2. Add ,"server": {"default": 1} to the client section as indicated in black below, and save. Don't forget the initial comma. This addition is important for initial prototyping, but must be removed when the device is deployed on your production platform.

    {
      "config": {
        "sys": {
          "factory": 1
        },
        "id": {
          "dsn": "AC000W123456789",
          "rsa_pub_key": "-----BEGIN RSA PUBLIC KEY-----\nMIIB...
        },
        "client": {
          "region": "US",
          "server": {
              "default": 1
          }
        },
        "oem": {
          "oem": "0aaa111e",
          "model": "linuxevb",
          "key": "UT9...
        }
      }
    }
    

7. Move devd.conf

Move devd.conf from ~/ to ~/ayla/config:

$ sudo mv devd.conf ~/ayla/config/devd.conf

Connect & Register

  1. Reboot your RPi:

    sudo reboot now

    After the RPi reboots, you will not be able to ssh to it immediately. This is normal. Here's what happens: During a reboot, Raspbian runs the Ayla Agent. The agent prevents Raspbian from re-connecting wirelessly to your LAN. Instead, the agent broadcasts the SSID of its own LAN, inviting you to connect via your mobile device. Once you do, you can use the Aura Mobile App to configure the agent to join your LAN which enables the agent to connect the RPi to the cloud.

  2. Tap Aura, and log into your Ayla account.
  3. Exit Aura, and tap Settings > Wi-Fi. You should be connected to your LAN, and you should see another LAN with an Ayla- prefix:



  4. Tap the Ayla LAN:



  5. Exit Settings > Wi-Fi, and tap Aura.
  6. On the Devices screen, tap the plus sign at top-right.



  7. Tap Ayla EVB (Legacy):



  8. Tap "I have the code", and, then, "I've powered the EVB":



  9. Tap your network:



  10. Enter the password, and tap Join:



  11. After approx. 30 seconds, the following screen should appear:


    (The image does not show a Raspberry Pi.)

  12. Tap Done. The Devices screen appears with the new Raspberry Pi:



Test the device

These directions show you how to use the Aura Mobile App to change the device product name, and how to test the default properties.

Product Name

  1. On the Devices screen, tap your new Raspberry Pi device.
  2. Tap the pencil at the top of the screen.
  3. Rename the device, and click Confirm.

Integer properties

When you set the input property value to n, appd sets the output property value to n x n.

  1. Scroll to the output property, and note the current value. It may be (null).
  2. Scroll to the input property, tap the current value, set it to 3, and tap Update Value.
  3. Scroll to the output property again, and note that it's new value is 9.

Boolean properties

When you set the Blue_LED and Green_LED property values to 1, appd sets the Blue_button property value to 1.

  1. Set Blue_LED to 1.
  2. Set Green_LED to 1.
  3. Note that Blue_button changes to 1.

String properties

When you set the cmd property value to "tree", appd sets the log property value to "tree".

  1. Set cmd to "tree".
  2. Note that log changes to "tree".

Decimal properties

When you set decimal_in to "3.14", appd sets decimal_out to "3.14".

  1. Set decimal_in to 3.14.
  2. Note that decimal_out changes to 3.14.

File properties

appd has two file properties: file_up and file_down. Useful for large data blobs such as log files and images, file properties can be of any size. Of the two file properties, appd enables you to test file_up only. When you set the boolean property file_up_test to one, appd uploads a file to file_up, and resets file_up_test to 0.

  1. Set file_up_test to 1.
  2. Note that file_up changes to a link.

Version property

appd has a version property where it stores the current appd software version. The Ayla Cloud reads and display this version. A user who needs to initiate an OTA update may find the version property useful.

Explore the example app

About Ayla daemons

The Ayla Linux Device Solution runs a small number of Linux daemons including the Ayla Linux Agent (devd), the example app (appd), the Ayla Connection Manager (cond) if your Linux client is using Wi-Fi, and the Ayla Logging Client (logd) if you want Ayla-related messages to be written not only to syslog, but also to the Ayla Cloud. They reside in /home/pi/ayla/bin:

$ ls -1 ~/ayla/bin/*d
/home/pi/ayla/bin/appd
/home/pi/ayla/bin/cond
/home/pi/ayla/bin/devd
/home/pi/ayla/bin/logd

Here is what they do:

DaemonDescription
appdThe example app illustrates how any host app might maintain a prop table and interact with the agent.
condThe Wi-Fi connection manager provides an abstraction layer between Ayla daemons and the native Wi-Fi driver.
devdThe Ayla Linux Agent provides secure connectivity to the Ayla Cloud.
logdThe Ayla Log Client parses /var/log/syslog for Ayla-tagged messages, and posts them to the Ayla Logging Service in the Ayla Cloud.

Three of these daemons are managed by normal Linux scripts in /etc/init.d:

$ ls -1 /etc/init.d/{cond,devd,logd}
/etc/init.d/cond
/etc/init.d/devd
/etc/init.d/logd

devd manages appd. When you stop devd, it stops appd:

$ sudo systemctl stop devd

And, when you start devd, it starts appd:

sudo systemctl start devd

devd also restarts appd if the latter fails.

Modify, make, and run

This section shows you how to modify, make, and run the example app. Recall that the app includes two integer properties called input and output, and that when you set input to x, the app sets output to x * x. The following steps show you how to modify this behavior so that when you set input to x, the app sets output to x + x.

  1. Open ~/device_linux_public/app/appd/appd.c for editing.
  2. Search for the following function:

    static int appd_input_set(struct prop *prop, const void *val, size_t len, const struct op_args *args) {
      ...
      if (input > 46340 || input < -46340) {
        output = -1;
      } else {
        output = input * input;
      }
      metadata = prop_metadata_alloc();
      prop_metadata_addf(metadata, "source", "%d x %d", input, input);
      opts.metadata = metadata;
      ...
    }
    
  3. Change input * input to input + input.
  4. Change %d x %d to %d + %d.
  5. Save the file.
  6. Build a new version of appd:

    $ cd ~/device_linux_public
    $ sudo make app
    
    The new appd resides in ~/device_linux_public/build/native/obj/app/appd.
  7. Stop devd. (devd stops appd.)

    $ sudo systemctl stop devd
    
  8. Make a copy of the original appd:

    $ sudo cp ~/ayla/bin/appd ~/ayla/bin/appd.original
    
  9. Copy your newly built version of appd to the directory where devd expects to find it:

    $ sudo cp ~/device_linux_public/build/native/obj/app/appd/appd ~/ayla/bin/appd
    
  10. Start devd. (devd starts appd.)

    $ sudo systemctl start devd  
    
  11. Test the new functionality.

What does appd do?

Consider the following diagram:

  1. appd defines an array of properties (e.g. Green_LED) associated with the device.
  2. The Ayla Cloud maintains an identical set of properties in the device's digital twin.
  3. appd and the Ayla Cloud work together to keep the properties synchronized.
  4. Each property includes a name, type, value, direction (To Device or From Device), etc.
  5. To Device (from the cloud) property values are sometimes related to command and control (e.g. turn on LED).
  6. From Device (to the cloud) property values are sometimes related to interrupts (e.g. the button was pressed).
  7. Typically, appd interacts with two interfaces: Agent API and Hardware API.
  8. The Agent API is devd which contributes secure connectivity to the cloud.
  9. The Hardware API depends on your hardware. For Linux on RPi, it includes the GPIO header.

Where are appd files?

In essence, the host application (appd) is composed of two source files and three Ayla libraries (mostly libapp.a):

~/device_linux_public/app/appd/main.c
~/device_linux_public/app/appd/appd.c
~/device_linux_public/build/native/obj/lib/app/libapp.a
~/device_linux_public/build/native/obj/lib/ayla/libayla.a
~/device_linux_public/build/native/obj/lib/platform/libplatform.a

The source files for the libraries are in the following directories:

~/device_linux_public/lib/app
~/device_linux_public/lib/ayla
~/device_linux_public/lib/platform

The host application also includes third-party libraries. See the Makefile. To view this file, contact your Ayla Representative to set up an Ayla GitHub account.

Tutorials

Implement Green_LED

This tutorial shows you how to implement a green LED for the existing Green_LED property.

Wire a Green LED

  1. Shutdown your RPi with sudo shutdown now.
  2. Wire the GPIO pins on your RPi to a breadboard, adding a green LED and a 220 Ω resister as seen in the diagram below.



  3. Restart your RPi.

Test with green_led.c

  1. View GPIO pin schemes:

    $ gpio readall
    We are using the wPi scheme where wPi 1 == BCM 18.
  2. Create a ~/ayla_tests directory
  3. Create a text file called ~/ayla_tests/green_led.c with the following code:

    #include <stdio.h>
    #include <wiringPi.h>
    #define GREEN_LED 1
    int main(void) {
      printf("Starting program\n");
      wiringPiSetup();
      pinMode(GREEN_LED, OUTPUT);
      for(;;) {
        digitalWrite(GREEN_LED, HIGH);
        delay(500);
        printf("High\n");
        digitalWrite(GREEN_LED,  LOW);
        delay(500);
        printf("Low\n");
      }
      return 0;
    }
    
  4. Build the program:

    $ gcc -Wall -o green_led green_led.c -lwiringPi
    
  5. Run the program to verify that you can control the LED from a program written in C. The LED should blink.

    ./green_led
    
  6. Press Ctrl-C to stop the program.

Modify Makefile

  1. Open ~/device_linux_public/app/appd/Makefile for editing.
  2. Scroll to the section called "List of libraries to link."
  3. Add wiringPi (with an uppercase 'P').

    LIBS = ssl crypto curl jansson wiringPi
    
  4. Save the file.

Modify appd.c

  1. Open ~/device_linux_public/app/appd/appd.c for editing.
  2. Include the wiringPi.h header file:

    #include <wiringPi.h>
    
  3. Specify a GPIO pin for the green LED:

    #define GREEN_LED 1
    
  4. Scroll to app_prop_table, find the entry for the Green_LED, and modify the set field:

    {
      .name = "Green_LED",
      .type = PROP_BOOLEAN,
      .set = appd_green_led_set,
      .send = prop_arg_send,
      .arg = &green_led,
      .len = sizeof(green_led),
      .ads_failure_cb = appd_prop_ads_failure_cb,
    },
    
  5. Add the following function to the file before app_prop_table:

    static int appd_green_led_set(struct prop \*prop, const void \*val, size_t len, const struct op_args \*args) {
      if (prop_arg_set(prop, val, len, args) != ERR_OK) {
        return -1;
      }
      digitalWrite(GREEN_LED, green_led);
      return 0;
    }
    
  6. Scroll to the appd_start function, and add the following:

    wiringPiSetup();
    pinMode(GREEN_LED, OUTPUT);
    
  7. Save the file.

Make, run, and test appd

Make and run appd:

$ cd ~/device_linux_public/
$ sudo make app
$ sudo systemctl stop devd
$ sudo cp ~/device_linux_public/build/native/obj/app/appd/appd ~/ayla/bin/appd
$ sudo systemctl start devd

Test the new functionality by toggling the Green LED property on/off in Aura, and verifying that the actual LED on the breadboard turns on/off.

Implement Blue_button

This tutorial shows you how to implement a blue button for the existing Blue_button property.

Wire the Blue Button

  1. Shutdown your RPi.
  2. Wire the GPIO pins on your RPi to a breadboard, adding a button and a 10K Ω resister as seen in the diagram below.



  3. Restart your RPi.

Test with blue_button_poll.c

  1. View GPIO pin schemes:

    $ gpio readall
    We are using the wPi scheme where wPi 6 == BCM 25.
  2. Create ~/ayla_tests/blue_button_poll.c with the following code:

    #include <stdio.h>
    #include <wiringPi.h>
    #define GREEN_LED 1
    #define BLUE_BUTTON 6
    int main(void) { printf("Starting program\n"); wiringPiSetup(); pinMode(GREEN_LED, OUTPUT); pinMode(BLUE_BUTTON, INPUT); for(;;) { if(digitalRead(BLUE_BUTTON) == LOW) digitalWrite(GREEN_LED, HIGH); else digitalWrite(GREEN_LED, LOW); } return 0; }
  3. Build the program:

    $ gcc -Wall -o blue_button_poll blue_button_poll.c -lwiringPi
    
  4. Run the program to verify that the button controls the LED.

    ./blue_button_poll
    
  5. Press Ctrl-C to stop the program.

Test with blue_button_isr.c

Create and test blue_button_isr.c.

#include <stdio.h>
#include <wiringPi.h>
#define GREEN_LED 1
#define BLUE_BUTTON 6

void blue_button_isr(void) {
  if(digitalRead(BLUE_BUTTON) == LOW) {
    digitalWrite(GREEN_LED, HIGH);
  } else {
    digitalWrite(GREEN_LED, LOW);
  }
}

int main(void) {
  printf("Starting program\n");
  wiringPiSetup();
  pinMode(GREEN_LED, OUTPUT);
  pinMode(BLUE_BUTTON, INPUT);
  wiringPiISR(BLUE_BUTTON, INT_EDGE_BOTH, &blue_button_isr);
  for(;;) {
    delay(1000);
    printf("Awake\n");
  }
  return 0;
}

Modify appd.c

  1. Open ~/device_linux_public/app/appd/appd.c for editing.
  2. Specify a GPIO pin for the blue button:

    #define BLUE_BUTTON 6
    
  3. Add the following function:

    void blue_button_isr(void) {
      if(digitalRead(BLUE_BUTTON) == LOW) {blue_button = 1;}
      else {blue_button = 0;}
      prop_send_by_name("Blue_button");
    }
    
  4. Scroll to the appd_start function, and add the following after wiringPiSetup():

    pinMode(BLUE_BUTTON, INPUT);
    wiringPiISR(BLUE_BUTTON, INT_EDGE_BOTH, &blue_button_isr);
    
  5. Save the file.

Make, run, and test appd

Make and run appd:

$ cd ~/device_linux_public/
$ sudo make app
$ sudo systemctl stop devd
$ sudo cp ~/device_linux_public/build/native/obj/app/appd/appd ~/ayla/bin/appd
$ sudo systemctl start devd

Test the new functionality. Look at the Blue_button property in Aura. Press and hold the blue button on the breadboard. See Blue_button change to true. Release the button. See the property value change to false.

Add Metadata

This tutorial shows you how to associate metadata (key:value pairs) with a property. Metadata limits include the following:

  • PROP_METADATA_MAX_ENTRIES - The maximum number of key/value pairs is 10.
  • PROP_METADATA_KEY_MAX_LEN - The maximum key length is 255 bytes.

See ~/device_linux_public/lib/app/props_internal.h..

Below are directions for associating the following metadata with the Blue_button property:

KeyValue
buttonSizesmall
buttonDistributorElego
  1. Browse to the Developer Portal.
  2. Click View My Devices > Raspberry Pi > Blue_button > Datapoints, and note the absence of Metadata.



  3. Open ~/device_linux_public/app/appd/appd.c for editing.
  4. Scroll to the blue_button_isr function, and modify it like this:

    void blue_button_isr(void) {
      struct op_options opts = {.confirm = 1};
    
      if(digitalRead(BLUE_BUTTON) == LOW) {blue_button = 1;}
      else {blue_button = 0;}
    
      struct prop_metadata \*metadata = prop_metadata_alloc();
      prop_metadata_add(metadata, "buttonSize", "small");
      prop_metadata_add(metadata, "buttonDistributer", "Elego");
      opts.metadata = metadata;
    
      struct prop \*prop = prop_lookup("Blue_button");
      prop->send(prop, 0, &opts);
      prop_metadata_free(metadata);
    }
    
  5. Make and run appd:

    $ cd ~/device_linux_public/
    $ sudo make app
    $ sudo systemctl stop devd
    $ sudo cp ~/device_linux_public/build/native/obj/app/appd/appd ~/ayla/bin/appd
    $ sudo systemctl start devd
    
  6. Click the Blue Button on your breadboard.
  7. View the Blue_button property in the Developer Portal:



  8. Tail ```syslog```:

    $ tail -f /var/log/syslog

    Note "metadata":{"buttonSize":"small","buttonDistributer":"Elego"}:

    Oct 11 14:03:12 raspberrypi appd: [debug-app] prop_val_send: Blue_button
    Oct 11 14:03:12 raspberrypi appd: [debug-app] data_send_json: {"cmd": 
    {"proto":"data","id":5,"op":"prop_send","opts":{"confirm":true},"args":[{"property": 
    {"name":"Blue_button","base_type":"boolean","value":1,"metadata": 
    {"buttonSize":"small","buttonDistributer":"Elego"},"dev_time_ms":1570802592534}}]}}
    

Add Red_button

This tutorial shows you how to implement a red button for a new Red_button property.

Wire a Red Button

  1. Shutdown your RPi.
  2. Wire the GPIO pins on your RPi to a breadboard, adding another button and another 10K Ω resister as seen in the diagram below. Whether or not the button is red, we will refer to it as the red button.



  3. Restart your RPi.

Test with red_button_isr.c

  1. View GPIO pin schemes:

    $ gpio readall
    We are using the wPi scheme where wPi 26 == BCM 12.
  2. Create ~/ayla_tests/red_button_isr.c with the following code:

    #include <stdio.h>
    #include <wiringPi.h>
    #define GREEN_LED 1
    #define RED_BUTTON 26
    
    void isr(void) {
      if(digitalRead(RED_BUTTON) == LOW) {
        digitalWrite(GREEN_LED, HIGH);
      } else {
        digitalWrite(GREEN_LED, LOW);
      }
    }
    
    int main (void) {
      printf("Start of program\n");
      wiringPiSetup();
      pinMode(GREEN_LED, OUTPUT);
      pinMode(RED_BUTTON, INPUT);
      wiringPiISR(RED_BUTTON, INT_EDGE_BOTH, &isr);
    
      for(;;) {
        delay(1000);
        printf("Awake\n");
      }
      return 0 ;
    }
    
  3. Build the program:

    $ gcc -Wall -o red_button_isr red_button_isr.c -lwiringPi
    
  4. Run the program to verify that the button can control the LED.

    ./red_button_isr
    
  5. Press Ctrl-C to stop the program.

Modify appd.c

  1. Open ~/device_linux_public/app/appd/appd.c for editing.
  2. Specify a GPIO pin for the red button:

    #define RED_BUTTON 26
    
  3. Add the following variable:

    static u8 red_button;
    
  4. Scroll to appd_prop_table, and add the following prop struct after the Blue_button entry:

    {
      .name = "Red_button",
      .type = PROP_BOOLEAN,
      .send = prop_arg_send,
      .arg = &red_button,
      .len = sizeof(red_button),
      .ads_failure_cb = appd_prop_ads_failure_cb,
    },
    
  5. Add the following function:

    void red_button_isr(void) {
      if(digitalRead(RED_BUTTON) == LOW) {red_button = 1;}
      else {red_button = 0;}
      prop_send_by_name("Red_button");
    }
    
  6. Scroll to the appd_start function, and add the following after wiringPiSetup():

    pinMode(RED_BUTTON, INPUT);
    wiringPiISR(RED_BUTTON, INT_EDGE_BOTH, &red_button_isr);
    
  7. Save the file.

Make and run appd (see error)

  1. Make and run appd:

    $ cd ~/device_linux_public/
    $ sudo make app
    $ sudo systemctl stop devd
    $ sudo cp ~/device_linux_public/build/native/obj/app/appd/appd ~/ayla/bin/appd
    $ sudo systemctl start devd
    
  2. tail syslog:

    $ tail -f /var/log/syslog
  3. Click the red button, and view the new output in syslog. The most important line is the following which indicates that the corresponding digital twin in the Ayla Cloud does not know about the new Red_button property.

    Sep  6 06:17:19 rpi appd: [debug-app] data_recv: {"cmd":{"proto":"data","id":9,"op":"nak","args":[{"err":"unknown_prop","name":"Red_button","dests":1,"op":"prop_send"}]}}
    

Create the Red_button property in the cloud

  1. Browse to the Developer Portal > View My Devices > Raspberry Pi
  2. Click Add, define the new Red_property, and click Save:



  3. Click the Red Button on the breadboard. The new cloud-based property should now reflect the button state.

Add a Trigger

This tutorial shows you how to add a trigger to the Red_button property.

  1. Browse to the Developer Portal.
  2. Click View My Devices > Raspberry Pi > Red_button > Triggers.
  3. Click Add, fill out the form, and click OK. Use this form as a guide:



  4. Click Add to add an application to the trigger.
  5. Add an email application.
  6. With appd running, click the Red Button on your breadboard.
  7. Check your email:

Implement Blue_LED

In preparation for Add a Schedule which controls both the green and blue LEDs, implement the Blue_LED in appd using BCM 16 which is wPi 27. See Implement Green_LED for reference. Here is the pinout:

Add a Schedule

This tutorial shows you how to create a Schedule for your Raspberry Pi to control the dates, times, durations, and intervals of RPi activity. Note the following:

  1. Creating a schedule requires no additional coding. Creating a schedule is a user activity.
  2. A single schedule can control many actions on the device. For example, a single schedule can turn on/off several LEDs, start up a motor, and turn on/off various sensors.
  3. You create schedules in the Developer Portal. When you save the Schedule, the Ayla Cloud downloads the schedule to the Ayla Linux Agent which is responsible for setting timers, waking up, and executing the scheduled actions.
  4. Schedule configurations are saved on the device in ~/ayla/config/appd.conf.startup.

Here are directions for creating a schedule:

  1. Browse to the Developer Portal.
  2. Click View My Devices > Raspberry Pi > Schedules.
  3. Click Add, fill out the form, and click OK. Use this form as a guide:



  4. The 2-second interval means this schedule will wake up every 2 seconds. The 1-second duration means that actions (as yet unspecified) can take place during a 1 second window.
  5. Click the new schedule:



  6. Click the Actions tab:



  7. Create the following two actions:






  8. Click the Settings tab, and click OK. If devd and appd are running, the Green LED on your RPi should begin to blink on/off every 1 second.
  9. Run appd in debug mode to see on/off messages.
  10. Verify datapoints in Aura, or in the Developer Portal.
  11. Add the following two new actions to the RPI Activity Schedule.






  12. Test the schedule. It should blink like this:

Explore Serial I/O

To demonstrates serial I/O between your host application (appd) running on your Raspberry Pi and a small program running on an Arduino board, this tutorial implements the following use case: When a user clicks either of the buttons on the breadboards, or toggles the twin_led property in the Ayla Cloud, both orange LEDs turn on or off in unison:


The following video demonstrates:

The tutorial builds the use case in three phases:

  1. Build an Arduino program that turns the Arduino LED on/off.
  2. Build an Arduino program and an RPi program that coordinate turning both LEDs on/off in unison.
  3. Merge parts of the RPi program into appd to accomplish the full use case.

Learn how to install the Arduino IDE onto your RPi:

  1. Connect to your RPi via VNC Viewer.
  2. In the terminal, run sudo apt-get update.
  3. In the browser, browse to Arduino Software.
  4. Download the Linux ARM version.
  5. In File Manager, navigate to the Downloads folder.
  6. Right-click on arduino-1.8.8-linuxarm.tar.xz, and click Extract Here.
  7. Right-click on the extracted folder, and click Open in Terminal.
  8. Run sudo ./install.sh. Ignore the following error:

        $ sudo ./install.sh
        Adding desktop shortcut, menu item and file associations for Arduino IDE...touch: cannot touch 
        '/root/.local/share/applications/mimeapps.list': No such file or directory
        /usr/bin/xdg-mime: 803: /usr/bin/xdg-mime: cannot create 
        /root/.local/share/applications/mimeapps.list.new: Directory nonexistent
        done!
    
    Note that the installation process also creates the following work directory: /home/pi/Arduino. You can use this directory to store your Arduino sketches.
  9. From the Desktop, start the Arduino IDE:



Arduino Only

  1. Wire the Arduino side of the diagram above. Click the image to enlarge.
  2. Create an Arduino sketch called arduino-only:

    const int LED = 8;
    const int BUTTON = 2;
    volatile unsigned char led_val = LOW;
    volatile bool led_changed = false; 
    
    void setup() {
      pinMode(LED, OUTPUT);
      pinMode(BUTTON, INPUT);
      attachInterrupt(digitalPinToInterrupt(BUTTON), button_isr, CHANGE);
      Serial.begin(9600);
    }
    
    void loop() {  
      delay(1000);
    }
    
    void button_isr() {
      if(digitalRead(BUTTON) == HIGH) {
        led_val = (led_val == HIGH) ? (LOW) : (HIGH);
        digitalWrite(LED, led_val);
      }
    }
    
  3. Compile, load, and run the sketch:



  4. Test by pressing and releasing the button. The LED should turn on. Repeat. The LED should turn off:

Arduino and RPi

  1. Wire the RPi side of the diagram at the top of the page. Click the image to enlarge.
  2. Create an Arduino sketch called arduino-side:

    const int LED = 8;
    const int BUTTON = 2;
    volatile unsigned char led_val = LOW;
    volatile bool led_changed = false; 
    
    void setup() {
      pinMode(LED, OUTPUT);
      pinMode(BUTTON, INPUT);
      attachInterrupt(digitalPinToInterrupt(BUTTON), button_isr, CHANGE);
      Serial.begin(9600);
    }
    
    void loop() {
      
      if(led_changed) {
        led_changed = false;
        Serial.write(led_val);
        Serial.write("/n");
      }
    
      while (Serial.available() > 0) {
        int val = Serial.read();
        if(val == LOW || val == HIGH) {
          led_val = val;
          digitalWrite(LED, led_val);
        }
      }
    }
    
    void button_isr() {
      if(digitalRead(BUTTON) == HIGH) {
        led_val = (led_val == HIGH) ? (LOW) : (HIGH);
        digitalWrite(LED, led_val);
        led_changed = true;
      }
    }
    
  3. Compile, load, and run the sketch.
  4. Create a C program for the RPi called rpi-side:

    #include 
    #include 
    #include 
    #include 
    #define LED 29
    #define BUTTON 28
    
    unsigned char led_val = LOW;
    int serialFileDesc = 0;
    
    void button_isr(void) {
      if(digitalRead(BUTTON) == HIGH) {
        led_val = (led_val == HIGH) ? (LOW) : (HIGH);
        digitalWrite(LED, led_val);
        serialPutchar(serialFileDesc, led_val);
      }
    }
    
    int main(void) {
      printf("Starting program\n");
      wiringPiSetup();
      pinMode(LED, OUTPUT);
      pinMode(BUTTON, INPUT);
      serialFileDesc = serialOpen("/dev/ttyACM0", 9600);
      wiringPiISR(BUTTON, INT_EDGE_BOTH, &button_isr);
    
      for(;;) {
        unsigned char val = serialGetchar(serialFileDesc);
        if(val == LOW || val == HIGH) {
          led_val = val;
          digitalWrite(LED, led_val);
        }
      }
    
      serialClose(serialFileDesc);
      return 0;
    }
    
  5. Compile and run:

    $ gcc -Wall -o rpi-side rpi-side.c -lwiringPi
    $ ./rpi-side
    
    Alternately, you can run the program in the background with ./rpi-side & disown, and stop it with killall rpi-side.
  6. Test by pressing and releasing either button. Both LEDs should turn on. Repeat. Both LEDs should turn off:


  7. Use Ctl-C to exit rpi-side.

Arduino, RPi, and Ayla

Modify Makefile

  1. Open ~/device_linux_public/app/appd/Makefile for editing.
  2. Scroll to the section called "List of libraries to link."
  3. Add wiringPi and pthread:

    LIBS = ssl crypto curl jansson wiringPi pthread
    
  4. Save the file.

Create the twin_led property

  1. Browse to the [Ayla Devloper Portal](/system-administration/ayla-developer-portal/), and log in.
  2. Click View My Devices.
  3. Click the serial number of your device.
  4. Click Add, and create a property with the following attributes:

    AttributeValue
    Property TypeProperty
    Nametwin_led
    Display Nametwin_led
    Base TypeBoolean
    DirectionTo Device
    Scopeuser

    The new property looks like this:

Modify appd.c

  1. Open ~/device_linux_public/app/appd/appd.c for editing.
  2. Include the following header files:

    #include <wiringPi.h>
    #include <wiringSerial.h>
    #include <pthread.h>
    
  3. Add the following constants:

    #define TWIN_RPI_LED 29
    #define TWIN_RPI_BUTTON 28
    
  4. Add the following variables:

    static u8 twin_led_val;
    int serialFileDesc = 0;
    pthread_t twin_led_serial_rx_thread_id;
    
  5. Scroll to app_prop_table, and add the following prop struct instance:

    {
      .name = "twin_led",
      .type = PROP_BOOLEAN,
      .set = appd_twin_led_set,
      .send = prop_arg_send,
      .arg = &twin_led_val,
      .len = sizeof(twin_led_val),
      .ads_failure_cb = appd_prop_ads_failure_cb,
    },
    
  6. Add an appd_twin_led_set function to the file before app_prop_table:

    static int appd_twin_led_set(struct prop *prop, const void *val, size_t len, const struct op_args *args)
    {
      if (prop_arg_set(prop, val, len, args) != ERR_OK) {
        return -1;
      }
      digitalWrite(TWIN_RPI_LED, twin_led_val);
      serialPutchar(serialFileDesc, twin_led_val);
      return 0;
    }
    
    This function receives the new value for twin_led_val from the cloud, applies it to the LED, and sends it to the Arduino board.

  7. Add an appd_twin_rpi_button_isr function:

    void appd_twin_rpi_button_isr(void) {
      if(digitalRead(TWIN_RPI_BUTTON) == HIGH) {
        twin_led_val = (twin_led_val == HIGH) ? (LOW) : (HIGH);
        digitalWrite(TWIN_RPI_LED, twin_led_val);
        serialPutchar(serialFileDesc, twin_led_val);
        prop_send_by_name("twin_led");
      }
    }
    
    This function receives the new value for twin_led_val from the button, applies it to the LED, sends it to the Arduino board and the cloud.

  8. Add an appd_twin_led_serial_rx function:

    void *appd_twin_led_serial_rx(void *ptr) {
      for(;;) {
        unsigned char val = serialGetchar(serialFileDesc);
        if(val == LOW || val == HIGH) {
          twin_led_val = val;
          digitalWrite(TWIN_RPI_LED, twin_led_val);
          prop_send_by_name("twin_led");
        }
      }
    }
    
    This function receives the new value for twin_led_val from the Arduino board, applies it to the LED, and sends it to the cloud.

  9. Scroll to the appd_start function, and change as follows:

    int appd_start(void)
    {
      log_info("application starting");
    

    app_set_template_version(appd_template_version);

    wiringPiSetup();
    pinMode(TWIN_RPI_LED, OUTPUT);
    pinMode(TWIN_RPI_BUTTON, INPUT);
    wiringPiISR(TWIN_RPI_BUTTON, INT_EDGE_BOTH, &appd_twin_rpi_button_isr);
    serialFileDesc = serialOpen("/dev/ttyACM0", 9600);
    pthread_create(&twin_led_serial_rx_thread_id, NULL, appd_twin_led_serial_rx, NULL);

    return 0;
    }

  10. Scroll to the appd_exit function, and change as follows:

    void appd_exit(int status)
    {
      log_info("application exiting with status: %d", status);
      serialClose(serialFileDesc);
      pthread_cancel(twin_led_serial_rx_thread_id);
    }
    
  11. Save the file.
  12. Make appd, and run devd and appd:

  13. $ cd ~/device_linux_public/
    $ sudo make
    $ sudo systemctl stop devd
    $ sudo cp ~/device_linux_public/build/native/obj/app/appd/appd ~/ayla/bin/appd
    $ sudo systemctl start devd
    
    Your modified appd interacts with the arduino-side sketch you ran in the previous section on this page.

  14. Test the new functionality by toggling the twin_led property on/off in Aura, and verifying that the actual LEDs on the breadboards turns on/off. Clicking the buttons on either breadboard should do the same.

Perform OTA Updates

Ayla provides a mechanism for performing over-the-air (OTA) updates in order to replace the Ayla Agent (devd) and/or the host application (appd) running on your Ayla device with different (often newer) versions. This page discusses OTA updates.

How OTA updates work

Ayla does not define a particular file format for OTA image files. The Ayla Cloud and all Ayla device components view the file as opaque. As the following diagram illustrates, and the steps explain, only platform-specific OTA Custom Code needs to understand both the file format and how to use the contents of the file to update software.

  1. An admin creates an OTA image file.
  2. Using Ayla Dashboard Portal, the admin uploads the file to the Ayla Cloud, associating it with a digital twin.
  3. The admin initiates an OTA job, specifying the file.
  4. The Ayla Cloud tells the Ayla Agent on the device to initiate an OTA update (see serv_ota_exec). To view this file, contact your Ayla Representative to set up an Ayla GitHub account.
  5. The Ayla Agent launches the OTA Daemon (see ota_update.c). To view this file, contact your Ayla Representative to set up an Ayla GitHub account.
  6. The OTA Daemon downloads the OTA file.
  7. The OTA Daemon launches platform-specific OTA Custom Code (see platform_ota_apply). To view this file, contact your Ayla Representative to set up an Ayla GitHub account.
  8. The OTA Custom Code opens the OTA image file, and applies the update.
  9. The OTA Daemon resets the device (see platform_reset). To view this file, contact your Ayla Representative to set up an Ayla GitHub account.

OTA implementation

The OTA image file for the Ayla Platform on RPi is a .tar file of the ~/device_linux_public directory including all source files, and excluding the build directory. The custom code untars the file in /tmp, builds and replaces all Ayla daemons, and restarts them. Custom code includes the following:

 FileFunctionDescription
1.ota.c (To view this file, contact your Ayla Representative to set up an Ayla GitHub account)platform_ota_applyCalls the apply_ota.sh script.
2.apply_ota.sh (To view this file, contact your Ayla Representative to set up an Ayla GitHub account) Creates a temporary build directory.
Unpacks /tmp/ayla_ota.img into the directory.
Builds and replaces all daemons.
Starts the daemons.

Finally, the OTA Daemon resets the device.

Perform an OTA update

Change appd version

  1. Open a Secure Shell to your Raspberry Pi.
  2. Open appd.c:

    $ nano ~/device_linux_public/app/appd/appd.c 
    
  3. Change appd_version in appd.c (To view this file, contact your Ayla Representative to set up an Ayla GitHub account) to a new version:

    const char *appd_version = "appd_matts_linux_device_1_1";
    
  4. Modify appd source code, build, test, repeat.

Create the OTA image file

  1. When you are ready to perform an OTA update, change directory to ~/device_linux_public.
  2. Run make clean to delete the build directory.
  3. Change directory to ~/.
  4. Create an archive of the device_linux_public directory:

    $ cd ~/device_linux_public
    $ tar -cf ../appd_matts_linux_device_1_1.tar .
    
  5. Exit ssh, scp the tar file to your computer, and open ssh again for later:
    $ scp [email protected]:appd_matts_linux_device_1_1.tar .
    

Upload the OTA image file

  1. Browse to the Ayla Dashboard Portal, and log in.
  2. Click Devices in the sidebar. In order to perform an OTA update to a device, it must first be a member of a device group.
  3. Click Search Devices, fill in the form, and click Search.



  4. Click Create Group, fill in the form, and click Create.



  5. Click Groups in the top horizontal menu, and view your new group. Click Close.



  6. Clicdk OTA in the sidebar.
  7. Click Host MCU Images in the top horizontal menu.
  8. Click Create, fill in the form, and click Save:

Perform the OTA update

Before you launch the OTA update, you may want to ssh to your RPi, and tail -f /var/log/syslog so that you can watch activity. See a sample syslog at the bottom of this page.

  1. In Ayla Dashboard Portal, click the Create OTA Job icon for your new image on the Host MCU Images list:



  2. Fill in the form, and click Create.



    The job appears in the OTA Jobs list:



  3. Slide to find the right end of the job on the list, and click the Start icon:



    At the end of the OTA process, your RPi will reboot.

Check results

Once the OTA process completes, check the following:

  1. Ayla Dashboard Portal > OTA > OTA Jobs.



  2. Ayla Dashboard Portal > Devices > DSN.



  3. Ayla Developer Portal > Devices > DSN > Details.



  4. Sample syslog

    Feb  8 21:22:21 MattsLinuxDevice devd: [debug-client] ds_get_cmds_done: &#35;012{&#35;012    
    "cmds": [&#35;012        {&#35;012            "cmd": {&#35;012                "data": "{\"ota\": 
    {\"url\":\"https&colon;//ais.aylanetworks.com/device/t_otas/16588.json? 
    dsn=AC000W006420034\",\"type\":\"host_mcu\",\"ver\":\"appd_matts_linux_device_1_1\",\"size\":4505600,
    \"checksum\":\"640e42b7fd7685a3f32ec8a697fc3776\",\"source\":\"local\"}}",&#35;012                
    "id": 10303704,&#35;012                "method": "PUT",&#35;012                "resource": 
    "ota.json",&#35;012                "uri": "/cmd_post_process.json"&#35;012            }&#35;012        
    }&#35;012    ],&#35;012    "properties": [],&#35;012    "schedules": []&#35;012}
    Feb  8 21:22:21 MattsLinuxDevice devd: [debug-server] server_handle_req: PUT ota.json
    Feb  8 21:22:21 MattsLinuxDevice devd: [info-server] serv_ota_exec: starting OTA download/apply of version 
    appd_matts_linux_device_1_1
    Feb  8 21:22:21 MattsLinuxDevice devd: [debug-server] serv_rev_put_end: status 200
    Feb  8 21:22:21 MattsLinuxDevice devd: [debug2-client] ds_send: PUT https&colon;//ads- 
    dev.aylanetworks.com/devices/5319141/cmd_post_process.json?cmd_id=10303704&status=200
    Feb  8 21:22:21 MattsLinuxDevice devd: [debug-server] serv_ota_exec: Starting ota_update using args:
    Feb  8 21:22:21 MattsLinuxDevice devd: [debug-server] serv_ota_exec: ota_update
    Feb  8 21:22:21 MattsLinuxDevice devd: [debug-server] serv_ota_exec: -u
    Feb  8 21:22:21 MattsLinuxDevice devd: [debug-server] serv_ota_exec: 
    https&colon;//ais.aylanetworks.com/device/t_otas/16588.json?dsn=AC000W006420034
    Feb  8 21:22:21 MattsLinuxDevice devd: [debug-server] serv_ota_exec: -l
    Feb  8 21:22:21 MattsLinuxDevice devd: [debug-server] serv_ota_exec: 4505600
    Feb  8 21:22:21 MattsLinuxDevice devd: [debug-server] serv_ota_exec: -c
    Feb  8 21:22:21 MattsLinuxDevice devd: [debug-server] serv_ota_exec: 640e42b7fd7685a3f32ec8a697fc3776
    Feb  8 21:22:21 MattsLinuxDevice devd: [debug-server] serv_ota_exec: -s
    Feb  8 21:22:21 MattsLinuxDevice devd: [debug-server] serv_ota_exec: /var/run/devd/msg_sock
    Feb  8 21:22:21 MattsLinuxDevice devd: [debug-server] serv_ota_exec: -ar
    Feb  8 21:22:21 MattsLinuxDevice devd: [debug-client] http_client_send: Found bundle for host ads- 
    dev.aylanetworks.com: 0xfa0110 [can pipeline]
    Feb  8 21:22:21 MattsLinuxDevice devd: [debug-server] serv_ota_exec: -d
    Feb  8 21:22:21 MattsLinuxDevice devd: [debug-server] serv_ota_exec: -H
    Feb  8 21:22:21 MattsLinuxDevice devd: [debug-server] serv_ota_exec: x-Ayla-auth-key: Ayla1.0 
    N9TdYRwCml13W6ajl2H8fVovuVSs4D1cYW1V
    Feb  8 21:22:21 MattsLinuxDevice devd: [debug-client] http_client_send: Re-using existing connection! 
    (&#35;3) with host ads-dev.aylanetworks.com
    Feb  8 21:22:21 MattsLinuxDevice devd: [debug-client] http_client_send: Connected to ads- 
    dev.aylanetworks.com (18.235.138.13) port 443 (&#35;3)
    Feb  8 21:22:21 MattsLinuxDevice ota_update: [debug-ota] platform_ota_flash_write_open: opened file 
    /tmp/ayla_ota.img for writing
    Feb  8 21:22:21 MattsLinuxDevice ota_update: [debug-ota] dl_download_with_retry: ota download 1 times, 
    offset:0, total:4505600
    Feb  8 21:22:21 MattsLinuxDevice ota_update: [info-ota] dl_curl: downloading 
    https&colon;//ais.aylanetworks.com/device/t_otas/16588.json?dsn=AC000W006420034
    Feb  8 21:22:21 MattsLinuxDevice devd: [warning-client] file_event_poll: poll failed: Interrupted system 
    call
    Feb  8 21:22:21 MattsLinuxDevice devd: [warning-client] ds_run: poll error: Interrupted system call
    Feb  8 21:22:21 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug:   Trying 18.235.138.13...
    Feb  8 21:22:21 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug: TCP_NODELAY set
    Feb  8 21:22:21 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug: Connected to ais.aylanetworks.com 
    (18.235.138.13) port 443 (&#35;0)
    Feb  8 21:22:21 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug: ALPN, offering http/1.1
    Feb  8 21:22:21 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug: Cipher selection: 
    ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
    Feb  8 21:22:21 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug: successfully set certificate verify 
    locations:
    Feb  8 21:22:21 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug:   CAfile: /etc/ssl/certs/ca- 
    certificates.crt&#35;012  CApath: /etc/ssl/certs
    Feb  8 21:22:21 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug: TLSv1.2 (OUT), TLS header, 
    Certificate Status (22):
    Feb  8 21:22:21 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug: TLSv1.2 (OUT), TLS handshake, 
    Client hello (1):
    Feb  8 21:22:21 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug: TLSv1.2 (IN), TLS handshake, Server 
    hello (2):
    Feb  8 21:22:21 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug: TLSv1.2 (IN), TLS handshake, 
    Certificate (11):
    Feb  8 21:22:21 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug: TLSv1.2 (IN), TLS handshake, Server 
    key exchange (12):
    Feb  8 21:22:21 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug: TLSv1.2 (IN), TLS handshake, Server 
    finished (14):
    Feb  8 21:22:21 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug: TLSv1.2 (OUT), TLS handshake, 
    Client key exchange (16):
    Feb  8 21:22:21 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug: TLSv1.2 (OUT), TLS change cipher, 
    Client hello (1):
    Feb  8 21:22:21 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug: TLSv1.2 (OUT), TLS handshake, 
    Finished (20):
    Feb  8 21:22:21 MattsLinuxDevice devd: [debug-client] ds_client_parse_auth_token: received Ayla auth token: 
    36 bytes
    Feb  8 21:22:21 MattsLinuxDevice devd: [debug-client] http_client_send: Curl_http_done: called premature == 
    0
    Feb  8 21:22:21 MattsLinuxDevice devd: [debug-client] http_client_send: Connection &#35;3 to host ads- 
    dev.aylanetworks.com left intact
    Feb  8 21:22:21 MattsLinuxDevice devd: [debug-client] ds_client_send_done: PUT complete, HTTP status 200, 
    time 280ms, https&colon;//ads-dev.aylanetworks.com/devices/5319141/cmd_post_process.json? 
    cmd_id=10303704&status=200
    Feb  8 21:22:22 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug: TLSv1.2 (IN), TLS change cipher, 
    Client hello (1):
    Feb  8 21:22:22 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug: TLSv1.2 (IN), TLS handshake, 
    Finished (20):
    Feb  8 21:22:22 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug: SSL connection using TLSv1.2 / 
    ECDHE-RSA-AES128-GCM-SHA256
    Feb  8 21:22:22 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug: ALPN, server accepted to use 
    http/1.1
    Feb  8 21:22:22 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug: Server certificate:
    Feb  8 21:22:22 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug:  subject: C=US; ST=California; 
    L=Sunnyvale; O=Ayla Networks Inc; CN=&#42;.aylanetworks.com
    Feb  8 21:22:22 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug:  start date: Aug  1 18:14:56 2018 
    GMT
    Feb  8 21:22:22 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug:  expire date: Aug 31 18:44:55 2020 
    GMT
    Feb  8 21:22:22 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug:  subjectAltName: host 
    "ais.aylanetworks.com" matched cert's "&#42;.aylanetworks.com"
    Feb  8 21:22:22 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug:  issuer: C=US; O=Entrust, Inc.; 
    OU=See www.entrust.net/legal-terms; OU=(c) 2012 Entrust, Inc. - for authorized use only; CN=Entrust 
    Certification Authority - L1K
    Feb  8 21:22:22 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug:  SSL certificate verify ok.
    Feb  8 21:22:22 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug: GET /device/t_otas/16588.json? 
    dsn=AC000W006420034 HTTP/1.1&#35;015&#35;012Host: ais.aylanetworks.com&#35;015&#35;012Accept: 
    */*&#35;015&#35;012x-Ayla-auth-key: Ayla1.0 N9TdYRwCml13W6ajl2H8fVovuVSs4D1cYW1V
    Feb  8 21:22:22 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug: HTTP/1.1 200 OK
    Feb  8 21:22:22 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug: Date: Fri, 08 Feb 2019 21:22:22 GMT
    Feb  8 21:22:22 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug: Content-Type: application/octet- 
    stream;charset=binary
    Feb  8 21:22:22 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug: Transfer-Encoding: chunked
    Feb  8 21:22:22 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug: Connection: keep-alive
    Feb  8 21:22:22 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug: Server: Apache
    Feb  8 21:22:22 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug: ETag: 
    "640e42b7fd7685a3f32ec8a697fc3776"
    Feb  8 21:22:22 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug: Last-Modified: Wed, 14 Dec 2050 
    18:43:58 GMT
    Feb  8 21:22:22 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug: Range: bytes=0-4505599
    Feb  8 21:22:22 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug: Status: 200 OK
    Feb  8 21:22:22 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug: x-Ayla-auth-key: 
    N9TdYRwCml13W6ajl2H8fVovuVSs4D1cYW1V
    Feb  8 21:22:22 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug: X-Frame-Options: sameorigin
    Feb  8 21:22:22 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug: X-Rack-Cache: miss
    Feb  8 21:22:22 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug: X-Request-Id: 
    9f3919b02be711e987441963de067d41
    Feb  8 21:22:22 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug: X-Runtime: 0.264316
    Feb  8 21:22:22 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug: X-UA-Compatible: IE=Edge,chrome=1
    Feb  8 21:22:22 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug: Content-Security-Policy: frame- 
    ancestors dashboard-dev.aylanetworks.com
    Feb  8 21:22:22 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug:
    Feb  8 21:22:25 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug: Curl_http_done: called premature == 
    0
    Feb  8 21:22:25 MattsLinuxDevice ota_update: [debug-ota] dl_curl_debug: Connection &#35;0 to host 
    ais.aylanetworks.com left intact
    Feb  8 21:22:25 MattsLinuxDevice ota_update: [info-ota] dl_curl: status 200
    Feb  8 21:22:25 MattsLinuxDevice ota_update: [debug-ota] dl_curl: downloading from offset 0 finish, 
    transfer len:4505600
    Feb  8 21:22:25 MattsLinuxDevice ota_update: [debug-ota] dl_download_with_retry: download sucess, offset:0, 
    total:4505600
    Feb  8 21:22:25 MattsLinuxDevice ota_update: [info-ota] dl_verify: verified readback is correct
    Feb  8 21:23:08 MattsLinuxDevice devd: [debug-client] msg_server_handle_client_event: connected: fd=11
    Feb  8 21:23:08 MattsLinuxDevice devd: [debug-client] amsg_send_default_resp: msg.interface 7, msg.type 0, 
    msg.err 0
    Feb  8 21:23:08 MattsLinuxDevice ota_update: [debug-ota] ota_status: sent status 0 to 
    /var/run/devd/msg_sock
    Feb  8 21:23:08 MattsLinuxDevice ota_update: [info-ota] main: rebooting
    

Debugging

By default, devd starts/stops/restarts appd. This section explains how to decouple this default behavior so that you can run appd in foreground and debug mode.

Decouple appd

Here is how you decouple devd and appd:

  1. Stop devd and appd:

    $ sudo systemctl stop devd
    
  2. Open /etc/init.d/devd for editing.

    $ sudo nano /etc/init.d/devd
    
  3. Add -n to OPTIONS, and save the file:

    OPTIONS="--debug -n -c /home/pi/ayla/config/devd.conf"
    
  4. Start devd:

    $ sudo systemctl start devd
    Warning: devd.service changed on disk. Run 'systemctl daemon-reload' to reload units.
    
    Run systemctl daemon-reload as instructed:

    $ sudo systemctl daemon-reload
    
  5. Verify that devd is running:

    $ ps -A | grep -w devd
     3466 ?        00:00:00 devd
    
  6. Verify that appd is not running:

    $ ps -A | grep appd
    

Background mode

  1. Decouple devd and appd.
  2. Restart devd.

    $ sudo systemctl restart devd
    
  3. View appd command-line options:

    $ sudo ~/device_linux_public/build/native/obj/app/appd/appd -h
    /home/pi/device_linux_public/build/native/obj/app/appd/appd: invalid option -- 'h'
    Usage: appd
      Options:
        -c --factory_config <file>   Specify factory config file
        -s --startup_dir <dir>       Specify startup config directory
        -d --debug                   Run in debug mode
        -f --foreground              Don't detach daemon process, run in foreground
        -o --sockdir  <dir>          Specify socket directory
    
  4. Start appd:

    $ sudo &#126;/device_linux_public/build/native/obj/app/appd/appd -c /home/pi/ayla/config/appd.conf
    
  5. Verify that appd is running:

    $ ps -A | grep appd
     3581 ?        00:00:00 appd
    
  6. Stop devd:

    $ sudo systemctl stop devd
    
  7. Stop appd:

    $ sudo killall appd
    

Foreground mode

  1. Decouple devd and appd.

  2. Restart devd.

    $ sudo systemctl restart devd
    
  3. Run appd:

    $ sudo &#126;/device_linux_public/build/native/obj/app/appd/appd -f -c /home/pi/ayla/config/appd.conf

    Terminal output may look like this:

    [INF] appd::appd_init()  application initializing
    [INF] appd::conf_read()  read configuration from file: /home/pi/ayla/config/appd.conf.startup
    [INF] appd::msg_client_event_handler()  connected to cloud client
    [INF] appd::appd_start()  application starting
    [INF] appd::appd_connectivity_event()  Cloud connection UP
    [INF] appd::appd_prop_confirm_cb()  output = 0 send at 1545320451361 to dests 1 succeeded
    [INF] appd::appd_prop_confirm_cb()  output = 8 send at 1545320452132 to dests 1 succeeded
    
  4. Stop appd with Ctrl-C.

  5. Stop devd:

    $ sudo systemctl stop devd
    

Debug mode

  1. Decouple devd and appd.

  2. Restart devd.

    $ sudo systemctl restart devd
    
  3. Run appd:

    $ sudo &#126;/device_linux_public/build/native/obj/app/appd/appd -f -d -c /home/pi/ayla/config/appd.conf

    Terminal output may look like this:

    ```
    2018-09-10T12:49:01.436 [DBG] appd::app_set_conf_file()  factory config: /home/pi/ayla/config/appd.conf, 
    startup config dir: default
    2018-09-10T12:49:01.437 [DBG] appd::app_set_socket_directory()  socket dir: /run
    2018-09-10T12:49:01.473 [INF] appd::appd_init()  application initializing
    2018-09-10T12:49:01.474 [DBG] appd::conf_load()  no valid startup config: 
    /home/pi/ayla/config/appd.conf.startup
    2018-09-10T12:49:01.474 [INF] appd::conf_read()  read configuration from file: 
    /home/pi/ayla/config/appd.conf
    2018-09-10T12:49:01.475 [INF] appd::msg_client_event_handler()  connected to cloud client
    2018-09-10T12:49:01.476 [INF] appd::appd_start()  application starting
    2018-09-10T12:49:01.477 [DBG] appd::prop_cloud_status_changed()  resending prop: oem_host_version
    2018-09-10T12:49:01.478 [DBG] appd::prop_val_send()  oem_host_version
    ...
    ...
    ```
    
  4. Try changing some property values via Ayla Developer Portal or Aura Mobile App, and view the results in the terminal:

    2019-02-07T15:14:32.355 [DBG] appd::data_recv()  {"cmd":{"proto":"data","id":1,"op":"prop_update","args": 
    [{"property":{"base_type":"boolean","name":"Blue_LED","value":0}}],"opts":{"source":1}}}
    2019-02-07T15:14:32.355 [DBG] appd::data_cmd_parse()  {"proto":"data","id":1,"op":"prop_update","args": 
    [{"property":{"base_type":"boolean","name":"Blue_LED","value":0}}],"opts":{"source":1}}, protocol data
    2019-02-07T15:14:32.355 [DBG] appd::data_recv_data()  {"proto":"data","id":1,"op":"prop_update","args": 
    [{"property":{"base_type":"boolean","name":"Blue_LED","value":0}}],"opts":{"source":1}}, recv_request_id 1
    2019-02-07T15:14:32.355 [DBG] appd::prop_arg_set()  Blue_LED = 0
    
  5. Stop appd with Ctrl-C.

  6. Stop devd:

    $ sudo systemctl stop devd