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
-
Obtain a Raspberry Pi. We used a Raspberry Pi 3 Model B+.
-
Download Raspbian Lite. Do not unzip. We used raspbian_lite-2018-04-19.
-
Download Etcher to your computer, and install it.
-
Insert the MicroSD card into a card reader, and insert the reader into a USB port on your computer:
-
Run Etcher, and flash the Raspian image onto the MicroSD card.
-
In a terminal, access the
boot
directory (e.g.cd /Volumes/boot
orcd /media/matt/boot
). -
Enable serial communication by appending
enable_uart=1
to config.txt. -
Enable Secure Shell by creating an empty ssh text file with
touch ssh
. -
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
. -
Unmount the card, remove it from the reader, insert it into the RPi (upside down), and power on.
-
Secure Shell to the RPi (or, optionally, use a serial/console cable):
-
Determine the RPi IP address. You can browse to the router manager page, or run
arp -a
in a shell. -
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. -
Type
yes
, and enterraspberry
for password. (Your username ispi
).
-
-
Determine whether
git
is installed. If not, install:$ git --version $ sudo apt-get update $ sudo apt-get install git -y
-
Determine whether
wiringpi
is installed. If not, install:$ gpio -v $ sudo apt-get install wiringpi
Install Ayla
Clone the Ayla repository
- In the secure shell, ensure that you are in your home directory (e.g.
/home/pi
). - 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
- View the release history, and, if the latest release is not
adc-1.7
, getadc-1.7
:
$ cd device_linux_public $ git log $ git checkout 5a4c0760b379a4c3cbbc698252d24e2b1286b51b
Edit ayla_install.sh
- Copy ayla_install.sh to your home directory:
$ cd ~ $ cp ~/device_linux_public/dev_kit/raspberry_pi/ayla_install.sh .
- Open the file for editing, and set ayla_src_dir:
ayla_src_dir="/home/pi/device_linux_public"
- 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
- Open
device_linux_public/app/appd/appd.c
. - Search for
appd_template_version
. - Replace the current value with
linux-v1.7
to enableappd
to identify your template. - Save the file.
Install the Ayla Edge Solution
- Create a dummy
devd.conf
file required byayla_install.sh
:
$ touch devd.conf
- View installation options:
$ ./ayla_install.sh -h
- 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.
- Include
- 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
- Browse to the Ayla Dashboard Portal, and log in.
- Click Factory Actions in the sidebar.
- Click the Reserve DSNs button.
- For Model, select
AY001MRT1-Linux Software Agent
. - In the textbox on the right, select 1.
- Click Submit. Ayla reserves for you a unique Device Serial Number (DSN) (e.g. AC000W123456789).
- Download the archive file to your computer.
- Unzip the archive file to extract the XML file.
- 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
- On your computer, create a text file called
oem_info
. - 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
- Replace
myRegion
with US, EU, or CN. - Replace
myOemId
with your oemId (see Ayla Dashboard Portal > OEM Profile > OEM ID). - Replace
myOemModel
with thelinuxevb
. - Replace
myOemSecret
with your oemSecret (see Ayla Dashboard Portal > OEM Profile > OEM Secret) - Leave the other values alone, and save.
- Secure Copy the file to
/home/pi
on your RPi:
$ scp oem_info [email protected]:
3. Make the config_gen utility
- On your RPi, change directory to your Ayla source directory:
$ cd ~/device_linux_public
- Build config_gen.
$ sudo make host_utils
The newly built utility is in~/device_linux_public/build/native/utils
.
4. Run config_gen
- View command-line options:
$ cd ~ $ ./device_linux_public/build/native/utils/config_gen
- 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
- Open
devd.conf
for editing. - Add
,"server": {"default": 1}
to theclient
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
- 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.
- Tap Aura, and log into your Ayla account.
- Exit Aura, and tap Settings > Wi-Fi. You should be connected to your LAN, and you should see another LAN with an
Ayla-
prefix:
- Tap the Ayla LAN:
- Exit Settings > Wi-Fi, and tap Aura.
- On the Devices screen, tap the plus sign at top-right.
- Tap Ayla EVB (Legacy):
- Tap "I have the code", and, then, "I've powered the EVB":
- Tap your network:
- Enter the password, and tap Join:
- After approx. 30 seconds, the following screen should appear:
(The image does not show a Raspberry Pi.) - 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
- On the Devices screen, tap your new Raspberry Pi device.
- Tap the pencil at the top of the screen.
- 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.
- Scroll to the output property, and note the current value. It may be (null).
- Scroll to the input property, tap the current value, set it to 3, and tap Update Value.
- 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.
- Set Blue_LED to 1.
- Set Green_LED to 1.
- 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".
- Set cmd to "tree".
- Note that log changes to "tree".
Decimal properties
When you set decimal_in to "3.14", appd
sets decimal_out to "3.14".
- Set decimal_in to 3.14.
- 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.
- Set file_up_test to 1.
- 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:
Daemon | Description |
---|---|
appd | The example app illustrates how any host app might maintain a prop table and interact with the agent. |
cond | The Wi-Fi connection manager provides an abstraction layer between Ayla daemons and the native Wi-Fi driver. |
devd | The Ayla Linux Agent provides secure connectivity to the Ayla Cloud. |
logd | The 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.
- Open
~/device_linux_public/app/appd/appd.c
for editing. - 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; ... }
- Change
input * input
toinput + input
. - Change
%d x %d
to%d + %d
. - Save the file.
- 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
. - Stop devd. (devd stops appd.)
$ sudo systemctl stop devd
- Make a copy of the original appd:
$ sudo cp ~/ayla/bin/appd ~/ayla/bin/appd.original
- 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
- Start devd. (devd starts appd.)
$ sudo systemctl start devd
- Test the new functionality.
What does appd do?
Consider the following diagram:
appd
defines an array of properties (e.g. Green_LED) associated with the device.- The Ayla Cloud maintains an identical set of properties in the device's digital twin.
appd
and the Ayla Cloud work together to keep the properties synchronized.- Each property includes a name, type, value, direction (
To Device
orFrom Device
), etc. To Device
(from the cloud) property values are sometimes related to command and control (e.g. turn on LED).From Device
(to the cloud) property values are sometimes related to interrupts (e.g. the button was pressed).- Typically,
appd
interacts with two interfaces: Agent API and Hardware API. - The Agent API is
devd
which contributes secure connectivity to the cloud. - 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
- Shutdown your RPi with
sudo shutdown now
. - Wire the GPIO pins on your RPi to a breadboard, adding a green LED and a 220 Ω resister as seen in the diagram below.
- Restart your RPi.
Test with green_led.c
- View GPIO pin schemes:
$ gpio readall
We are using the wPi scheme where wPi 1 == BCM 18. - Create a
~/ayla_tests
directory - 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; }
- Build the program:
$ gcc -Wall -o green_led green_led.c -lwiringPi
- Run the program to verify that you can control the LED from a program written in C. The LED should blink.
./green_led
- Press Ctrl-C to stop the program.
Modify Makefile
- Open
~/device_linux_public/app/appd/Makefile
for editing. - Scroll to the section called "List of libraries to link."
- Add wiringPi (with an uppercase 'P').
LIBS = ssl crypto curl jansson wiringPi
- Save the file.
Modify appd.c
- Open
~/device_linux_public/app/appd/appd.c
for editing. - Include the wiringPi.h header file:
#include <wiringPi.h>
- Specify a GPIO pin for the green LED:
#define GREEN_LED 1
- 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, },
- 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; }
- Scroll to the
appd_start
function, and add the following:
wiringPiSetup(); pinMode(GREEN_LED, OUTPUT);
- 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
- Shutdown your RPi.
- Wire the GPIO pins on your RPi to a breadboard, adding a button and a 10K Ω resister as seen in the diagram below.
- Restart your RPi.
Test with blue_button_poll.c
- View GPIO pin schemes:
$ gpio readall
We are using the wPi scheme where wPi 6 == BCM 25. - 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; } - Build the program:
$ gcc -Wall -o blue_button_poll blue_button_poll.c -lwiringPi
- Run the program to verify that the button controls the LED.
./blue_button_poll
- 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
- Open
~/device_linux_public/app/appd/appd.c
for editing. - Specify a GPIO pin for the blue button:
#define BLUE_BUTTON 6
- 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"); }
- Scroll to the
appd_start
function, and add the following afterwiringPiSetup()
:
pinMode(BLUE_BUTTON, INPUT); wiringPiISR(BLUE_BUTTON, INT_EDGE_BOTH, &blue_button_isr);
- 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:
Key | Value |
---|---|
buttonSize | small |
buttonDistributor | Elego |
- Browse to the Developer Portal.
- Click View My Devices > Raspberry Pi > Blue_button > Datapoints, and note the absence of Metadata.
- Open
~/device_linux_public/app/appd/appd.c
for editing. - 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); }
- 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
- Click the Blue Button on your breadboard.
- View the Blue_button property in the Developer Portal:
- 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
- Shutdown your RPi.
- 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.
- Restart your RPi.
Test with red_button_isr.c
- View GPIO pin schemes:
$ gpio readall
We are using the wPi scheme where wPi 26 == BCM 12.
- 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 ; }
- Build the program:
$ gcc -Wall -o red_button_isr red_button_isr.c -lwiringPi
- Run the program to verify that the button can control the LED.
./red_button_isr
- Press Ctrl-C to stop the program.
Modify appd.c
- Open
~/device_linux_public/app/appd/appd.c
for editing. - Specify a GPIO pin for the red button:
#define RED_BUTTON 26
- Add the following variable:
static u8 red_button;
- 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, },
- 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"); }
- Scroll to the
appd_start
function, and add the following afterwiringPiSetup()
:
pinMode(RED_BUTTON, INPUT); wiringPiISR(RED_BUTTON, INT_EDGE_BOTH, &red_button_isr);
- Save the file.
Make and run appd (see error)
- 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
- tail
syslog
:
$ tail -f /var/log/syslog
- 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
- Browse to the Developer Portal > View My Devices > Raspberry Pi
- Click Add, define the new Red_property, and click Save:
- 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.
- Browse to the Developer Portal.
- Click View My Devices > Raspberry Pi > Red_button > Triggers.
- Click Add, fill out the form, and click OK. Use this form as a guide:
- Click Add to add an application to the trigger.
- Add an email application.
- With appd running, click the Red Button on your breadboard.
- 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:
- Creating a schedule requires no additional coding. Creating a schedule is a user activity.
- 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.
- 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.
- Schedule configurations are saved on the device in
~/ayla/config/appd.conf.startup
.
Here are directions for creating a schedule:
- Browse to the Developer Portal.
- Click View My Devices > Raspberry Pi > Schedules.
- Click Add, fill out the form, and click OK. Use this form as a guide:
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.
- Click the new schedule:
- Click the Actions tab:
- Create the following two actions:
- 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.
- Run appd in debug mode to see on/off messages.
- Verify datapoints in Aura, or in the Developer Portal.
- Add the following two new actions to the RPI Activity Schedule.
- 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:
- Build an Arduino program that turns the Arduino LED on/off.
- Build an Arduino program and an RPi program that coordinate turning both LEDs on/off in unison.
- Merge parts of the RPi program into appd to accomplish the full use case.
Learn how to install the Arduino IDE onto your RPi:
- Connect to your RPi via VNC Viewer.
- In the terminal, run
sudo apt-get update
. - In the browser, browse to Arduino Software.
- Download the Linux ARM version.
- In File Manager, navigate to the Downloads folder.
- Right-click on
arduino-1.8.8-linuxarm.tar.xz
, and clickExtract Here
. - Right-click on the extracted folder, and click
Open in Terminal
. - 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. - From the Desktop, start the Arduino IDE:
Arduino Only
- Wire the Arduino side of the diagram above. Click the image to enlarge.
- 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); } }
- Compile, load, and run the sketch:
- Test by pressing and releasing the button. The LED should turn on. Repeat. The LED should turn off:
Arduino and RPi
- Wire the RPi side of the diagram at the top of the page. Click the image to enlarge.
- 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; } }
- Compile, load, and run the sketch.
- 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; }
- 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 withkillall rpi-side
. - Test by pressing and releasing either button. Both LEDs should turn on. Repeat. Both LEDs should turn off:
- Use
Ctl-C
to exitrpi-side
.
Arduino, RPi, and Ayla
Modify Makefile
- Open
~/device_linux_public/app/appd/Makefile
for editing. - Scroll to the section called "List of libraries to link."
- Add wiringPi and pthread:
LIBS = ssl crypto curl jansson wiringPi pthread
- Save the file.
Create the twin_led property
- Browse to the [Ayla Devloper Portal](/system-administration/ayla-developer-portal/), and log in.
- Click View My Devices.
- Click the serial number of your device.
- Click Add, and create a property with the following attributes:
Attribute Value Property Type Property Name twin_led Display Name twin_led Base Type Boolean Direction To Device Scope user
The new property looks like this:
Modify appd.c
- Open
~/device_linux_public/app/appd/appd.c
for editing. - Include the following header files:
#include <wiringPi.h> #include <wiringSerial.h> #include <pthread.h>
- Add the following constants:
#define TWIN_RPI_LED 29 #define TWIN_RPI_BUTTON 28
- Add the following variables:
static u8 twin_led_val; int serialFileDesc = 0; pthread_t twin_led_serial_rx_thread_id;
- Scroll to
app_prop_table
, and add the followingprop
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, },
- Add an
appd_twin_led_set
function to the file beforeapp_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.
- 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. - 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.
- 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;
} - 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); }
- Save the file.
- Make
appd
, and rundevd
andappd
: - 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.
$ 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 devdYour modified
appd
interacts with the arduino-side
sketch you ran in the previous section on this page.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.
- An admin creates an OTA image file.
- Using Ayla Dashboard Portal, the admin uploads the file to the Ayla Cloud, associating it with a digital twin.
- The admin initiates an OTA job, specifying the file.
- 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.
- 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.
- The OTA Daemon downloads the OTA file.
- 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.
- The OTA Custom Code opens the OTA image file, and applies the update.
- 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:
File | Function | Description | |
---|---|---|---|
1. | ota.c (To view this file, contact your Ayla Representative to set up an Ayla GitHub account) | platform_ota_apply | Calls 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
- Open a Secure Shell to your Raspberry Pi.
- Open
appd.c
:
$ nano ~/device_linux_public/app/appd/appd.c
- 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";
- Modify
appd
source code, build, test, repeat.
Create the OTA image file
- When you are ready to perform an OTA update, change directory to
~/device_linux_public
. - Run
make clean
to delete thebuild
directory. - Change directory to
~/
. - Create an archive of the
device_linux_public
directory:
$ cd ~/device_linux_public $ tar -cf ../appd_matts_linux_device_1_1.tar .
- Exit
ssh
,scp
the tar file to your computer, and openssh
again for later:$ scp [email protected]:appd_matts_linux_device_1_1.tar .
Upload the OTA image file
- Browse to the Ayla Dashboard Portal, and log in.
- 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. - Click
Search Devices
, fill in the form, and click Search.
- Click
Create Group
, fill in the form, and click Create.
- Click Groups in the top horizontal menu, and view your new group. Click Close.
- Clicdk
OTA
in the sidebar. - Click
Host MCU Images
in the top horizontal menu. - 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.
- In Ayla Dashboard Portal, click the Create OTA Job icon for your new image on the Host MCU Images list:
- Fill in the form, and click Create.
The job appears in theOTA Jobs
list:
- 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:
-
Ayla Dashboard Portal > OTA > OTA Jobs.
-
Ayla Dashboard Portal > Devices > DSN.
-
Ayla Developer Portal > Devices > DSN > Details.
-
Sample syslog
Feb 8 21:22:21 MattsLinuxDevice devd: [debug-client] ds_get_cmds_done: #012{#012 "cmds": [#012 {#012 "cmd": {#012 "data": "{\"ota\": {\"url\":\"https://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\"}}",#012 "id": 10303704,#012 "method": "PUT",#012 "resource": "ota.json",#012 "uri": "/cmd_post_process.json"#012 }#012 }#012 ],#012 "properties": [],#012 "schedules": []#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://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://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! (#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 (#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://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 (#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#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 #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://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=*.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 "*.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#015#012Host: ais.aylanetworks.com#015#012Accept: */*#015#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 #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
:
- Stop devd and appd:
$ sudo systemctl stop devd
- Open /etc/init.d/devd for editing.
$ sudo nano /etc/init.d/devd
- Add -n to OPTIONS, and save the file:
OPTIONS="--debug -n -c /home/pi/ayla/config/devd.conf"
- Start devd:
$ sudo systemctl start devd Warning: devd.service changed on disk. Run 'systemctl daemon-reload' to reload units.
Runsystemctl daemon-reload
as instructed:
$ sudo systemctl daemon-reload
- Verify that devd is running:
$ ps -A | grep -w devd 3466 ? 00:00:00 devd
- Verify that appd is not running:
$ ps -A | grep appd
Background mode
- Decouple
devd
andappd
. - Restart devd.
$ sudo systemctl restart devd
- 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
- Start appd:
$ sudo ~/device_linux_public/build/native/obj/app/appd/appd -c /home/pi/ayla/config/appd.conf
- Verify that appd is running:
$ ps -A | grep appd 3581 ? 00:00:00 appd
- Stop devd:
$ sudo systemctl stop devd
- Stop appd:
$ sudo killall appd
Foreground mode
-
Decouple
devd
andappd
. -
Restart devd.
$ sudo systemctl restart devd
-
Run appd:
$ sudo ~/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
-
Stop appd with
Ctrl-C
. -
Stop devd:
$ sudo systemctl stop devd
Debug mode
-
Decouple
devd
andappd
. -
Restart devd.
$ sudo systemctl restart devd
-
Run appd:
$ sudo ~/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 ... ... ```
-
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
-
Stop appd with
Ctrl-C
. -
Stop devd:
$ sudo systemctl stop devd
Updated over 2 years ago