Ayla Development Kit-ESP32C3 Module

Ayla Development Kit provides an opportunity (1) to experiment with Ayla IoT Cloud features, and (2) to modify, build, flash, and run the example host application in preparation for connecting your own devices and gateways. The kit is composed of a STM32 Nucleo Board and an Ayla Shield:

The Ayla Shield includes an Ayla Wi-Fi Production module which is a communication module pre-loaded with an Ayla Agent that enables secure communication with the Ayla Cloud. Production modules are one of several options for connecting devices and gateways to the Cloud.

Contact Ayla to order a dev kit.

About this guide

This guide helps you create a user account with EndUser access rights in the Ayla Public Account.

Next, it shows you how to connect your kit to the Ayla Public Cloud Account, and register it to your user account:

Then, it helps you explore your kit using the Aura Mobile App, Ayla Developer Portal, and Ayla Dashboard Portal:

Connect your kit

Connecting your dev kit to the Ayla Cloud takes only a few steps:

  1. Connect your mobile device to a 2.4GHz Wi-Fi LAN.

  2. On your mobile device, get and install the "Ayla Aura Mobile App" from the App Store or Google Play.

  3. To create a user account with EndUser access rights in the Ayla Public Account, tap Sign Up, fill in the form, receive the verification email on your mobile device, and confirm. If you already have a user account in an Ayla Customer Account, then you can use that account. To configure Aura to communicate with this account, see these directions.

  4. Tap "+" to add a device:

  5. Tap Ayla Dev Kit:

  6. Enter the same Wi-Fi credentials as those used by your mobile device, and tap Continue:

  7. Take your Ayla Dev Kit out of the box.

  8. Plug the small end of the cable into the STM32 Nucleo board:

  9. Plug the large end into a USB outlet, tap continue, and then tap Join:

  10. Tap Done to see your new device on the Devices screen. Then, tap Ayla Dev Kit to see the Details screen:

Explore properties

This section helps you explore Ayla device properties. To start with, the Ayla Shield on your Ayla Development Kit has several important landmarks:

If you were the manufacturer of this device, you would decide which of these landmarks should be modeled in the Ayla Cloud. You might want the cloud to be aware when a user presses the blue button. And, you might want to cloud to be able to turn on/off the blue and green LEDs. So, you would designate these landmarks as device properties. The Ayla Cloud sees your Ayla Development Kit as a set of properties bundled into a digital twin:

Some of these properties (e.g. Blue_LED) do, indeed, represent device landmarks. Others (e.g. input & output) exist simply to demonstrate various property types: boolean, string, integer, decimal, and file. The following sections help you explore these properties.

Boolean properties

  1. Tap the Blue_LED property slider:

    The Blue LED on the dev kit illuminates. Tapping the slider sends an update to the device.

  2. Tap the Blue_LED slider On/Off several times to generate a history of values.

  3. Tap the Blue_LED name. The Property details screen appears. Pull down on the screen momentarily. The Datapoints list appears:


    A datapoint is a time-stamped property value.
  4. Tap the Green_LED property slider:


    The Green LED on the dev kit illuminates. Tapping this slider also sends an update *to the device*.
  5. Press the light-blue button on the Ayla Shield of the dev kit:


    The Blue_button property slider slides on.

    So, pressing the button on the kit sends an update *from the device*.

String properties

  1. Tap the white space to the right of the cmd property:


  2. Enter a string like community, and tap Update Value.


    Setting the cmd property sends a string value *to the device*.

  3. View the log property:


    The host app (on the device) sets log = cmd, and sends the string *from the device*.

  4. Tap the version property name:


    The Property Details screen displays three property attributes. The *Current Value* attribute represents the host (application) software version because another attribute (not seen on this screen), host_sw_version, is set to `true`.


Integer properties

  1. Tap the value to the right of the input property:



    A dialog box appears.

  2. Enter an integer like 5, and tap Update Value.



    Setting the input property sends an integer value to the device.

  3. View the output property:



    The host app (on the device) sets output = input * input, and sends the integer from the device.

Decimal properties

  1. Tap the value to the right of the decimal_in property:



    A dialog box appears.

  2. Enter a decimal like 2.71, and tap Update Value.



    Setting the decimalin property sends a decimal value _to the device.

  3. View the decimalout property:



    The host app (on the device) sets decimal_out = decimal_in, and sends the decimal _from the device
    .

File properties

  1. In the Ayla Developer Portal, on the Device Menu, click the Properties tab to display the "stream" properties:



  2. Set stream_up_len to 5000. The value will (almost immediately) change to zero. Setting stream_up_len to 5000 causes the Ayla Cloud to send the value 5000 to the host application on the dev kit. The host application responds by streaming 5000 bytes to the stream_up property in the Ayla Cloud. The 5000 bytes conform to a pattern similar to the following:

    "3D"3E"3F"3G"3H"3I"3J"...
    
  3. In the Display Name column, click the stream_up property.

  4. Click Download, and download the generated file to your computer.

  5. Open the file with a text editor to verify the pattern.

  6. In the Current Value column of the stream_down row, click click to update.

  7. Click Choose File, select the file you just downloaded, and click OK. The Ayla Cloud streams the file down to the host application on the dev kit. The host application does not store the file. Instead, it counts the number of bytes received, and sets stream_down_len to that count. It sets stream_down_match_len to the number of bytes that match the pattern originally uploaded. Both should be 5000. This behavior merely demonstrates file properties. You can customize this functionality in your own host application implementation.

Explore schedules

This section introduces you to Ayla schedules.

  1. Ensure that the Blue_LED property is off.



  2. Ensure that the time zone on the dev kit is set appropriately by clicking the Gear, and then Time Zone.



  3. Tap the Schedules button on the Device screen.



    The Schedules screen appears with one pre-made schedule called schedule_in.



  4. Tap schedule_in to display the Edit Schedule screen.



  5. Scroll to Schedule Actions:



    Note that this schedule sets Blue_LED to 1 at start date/time, and to 0 at end date/time.

  6. Scroll to Start Time, and set the time to a few minutes from now.

  7. Scroll to End Time, and set the time to a minute after Start Time.



  8. Scroll to Active, and activate the schedule:



  9. Tap Save Schedule at the bottom of the screen.

  10. Observe (on the dev kit and in Aura) Blue_LED glow at start time, and dim at end time.

Explore notifications

This section introduces you to push notifications of property or device conditions that you define. For example, you can configure the Ayla Cloud to send a push notification to your mobile device when the GreenLED property value changes, and/or when the Ayla Development Kit goes offline/online. For email and text message notifications, see Ayla Developer Portal. To get started with push notifications, tap the _Notifications button in Aura.

Property notifications

  1. Tap "+".
  2. Tap "Property notification".
  3. Configure the following fields:

    FieldValue
    Notification NameGreen LED Changed
    Notification MessageThe Green LED changed.
    ConditionWhen Green_LED has Changed.
    Send push notification to this device

  4. Tap Save Notifications.
  5. Turn on/off Green_LED. See a push notification similar to the following:



    Wait a few seconds before generating the next push notification.

  6. Uncheck Send push ..., and save again.

Device notifications

  1. Tap "+".
  2. Tap "Device notification".
  3. Configure the following fields:

    FieldValue
    Notification NameAyla Dev Kit Offline
    Eventon_connection_lost
    Threshhold300 (seconds)
    Notification MessageThe Ayla Dev Kit is offline.
    Send push notification to this device

  4. Tap Save Notifications.
  5. Disconnect the Ayla Dev Kit, and wait for a few minutes. See a push notification similar to the following:



  6. Uncheck Send push ..., and save again.

Explore device sharing

This section shows you how to share a device with another Ayla user account.

Granting access

  1. Tap Share Device at the bottom of the Device screen:



  2. Enter the email address for an existing Ayla user account:



  3. Choose capabilities:



    Note that Default is the same as Read Only.

  4. Optionally, choose a start and end date to define an active duration. Initially, leave this blank.

  5. Tap Create Share:



    You will see the following message:



  6. Tap Menu Menu > Shares:



    You will see the device under "Devices You Own" on the Shared Devices list:



  7. Check your email. You will receive an email from the Ayla Cloud similar to the following:

    Subject:Matt Hagen granted access to device with ID: AC000W000123456
    Message:Hello, Matt Hagen granted read access to the device with ID: AC000W000123456

    Note that each Ayla device has an id and a Device Serial Number (dsn). The value in the email is actually the dsn.

Receiving access

The person with whom the device is shared will see the device on their Aura Devices list:




They will also see the device under "Devices Shared To You" on the Shared Devices list:




With default (read-only) access, most functionality will be disabled:




They will, however, receive notifications:



Explore factory resets

A factory reset of your Ayla Development Kit reinitializes certain configuration parameters (e.g. Wi-Fi and Time Zone) to default values. For details about these configuration parameters, see Configuration.

Performing a factory reset is one step in the process of moving your dev kit from one LAN to another:

  1. Factory reset your Ayla Dev Kit via Aura (see Aura Factory Reset below).
  2. Connect your mobile device to the new LAN.
  3. Start with Connect your kit, Step 4, above.

There are several ways to perform a factory reset. Here are two:

Aura factory reset

Tap your device on the Aura Devices list, tap the gear (top-right), and tap Factory Reset:

Physical factory reset

The diagram shows you how to perform a physical factory reset of the dev kit:

Build environment

This section helps you download Ayla software and establish a build environment that enables you to iteratively modify, build, flash, and run the host application.

Host Application

The host application (ledevb.img) consists of demo.c linked to four Ayla libraries: libdemo.a, libayla.a, libtarget.a, and libcons.a. It runs on the MCU of the STM32 Nucleo board, and interfaces via SPI or UART serial communication with the Ayla Agent running on the Ayla production module affixed to the Ayla Shield:

demo.c defines a set of properties appropriate for the Ayla Dev Kit:

static struct prop prop_table[] =  {
  {"Blue_button", ATLV_BOOL, NULL, send_prop_with_meta, &blue_button, sizeof(blue_button)},
  {"Blue_LED", ATLV_BOOL, set_led, send_led, (void *)LED0, 1},
  {"Green_LED", ATLV_BOOL, set_led, send_led, (void *)LED1, 1},
  {"log", ATLV_UTF8, NULL, prop_send_generic, cmd_buf, 0},
  {"cmd", ATLV_UTF8, set_cmd, prop_send_generic, cmd_buf, 0},
  {"input", ATLV_INT, set_input, prop_send_generic, &input, sizeof(input)},
  {"output", ATLV_INT, NULL, prop_send_generic, &output, sizeof(output)},
  {"decimal_in", ATLV_CENTS, set_dec_in, prop_send_generic, &decimal_in, sizeof(decimal_in)},
  {"decimal_out", ATLV_CENTS, NULL, prop_send_generic, &decimal_out, sizeof(decimal_out)},
  {"schedule_in", ATLV_SCHED, demo_sched_set, NULL, &demo_sched[0]},
  {"stream_up", ATLV_LOC, NULL, demo_send_file_prop_with_meta, &stream_up_state, 0},
  {"stream_up_len", ATLV_INT, demo_set_length_up, prop_send_generic, &stream_up_len, sizeof(stream_up_len)},
  {"stream_down", ATLV_LOC, prop_dp_set, prop_dp_send, &stream_down_state, 0},
  {"stream_down_len", ATLV_UINT, NULL, prop_send_generic, &stream_down_state.next_off, sizeof(stream_down_state.next_off)},
  {"stream_down_match_len", ATLV_UINT, NULL, prop_send_generic, &stream_down_patt_match_len, sizeof(stream_down_patt_match_len)},
  {"version", ATLV_UTF8, NULL, send_version, NULL, 0},
  {"oem_host_version", ATLV_UTF8, NULL, prop_send_generic, template_version, sizeof(template_version) - 1},
};

When you connect your Ayla Dev Kit to the Ayla Cloud, the cloud instantiates a digital twin from a template (not shown) to model the kit. Client applications like Aura interact with the Ayla Dev Kit via the digital twin:

Ayla Host Library

The Ayla Host Library contains the source code and supporting files needed to customize, compile, link, download, and run the host application (ledevb.img) on the Ayla Dev Kit. The following diagram illustrates Ayla Host Library organization:

The following table provides an introductory description of the components that make up the host application.

ComponentDescription and Source Files
demo.cThis is the only file you need to modify as you experiment with the Ayla Dev Kit. It implements an array of properties (with supporting functions) supported by the host application. You can modify this array.
example/app/ledevb/demo.c
libdemo.aThese files compartmentalize host application functionality for better code organization. The factory reset code tells the Ayla Agent to "factory reset" when a user pushes the appropriate buttons on the dev kit. The polling code implements timers, callbacks, and continuous polling of the corresponding digital twin in the Ayla Cloud. The power management code puts the Ayla production module in standby mode, and wakes it up when needed. The image management code participates in over-the-air updates.
example/libdemo/demo_factory_reset.c
example/libdemo/demo_poll.c
example/libdemo/demo_power.c
example/libdemo/demo_img_mgmt.c
libcons.aThis library enables serial communication, primarily for debugging purposes, between your computer and the host app running on the MCU of the host board. Run screen /dev/ttyACM0 115200 or similar in a terminal to initiate communication, and press Ctl-A + k + y to terminate the session. Use the demo_log function to printf messages from the host app on the dev kit to a terminal on your computer. See the console_cmds array in console.c for a list of commands.
example/libcons/atty.c
example/libcons/cmd_handle.c
example/libcons/console.c
example/libcons/parse_argv.c
example/libcons/parse_hex.c
example/libcons/printf.c
libayla.aThis platform-independent library implements the Ayla Agent API. Below are just a few examples of important API functions and structs used by the host application. Name prefixes indicate the corresponding library file:
void host_event_register(struct host_event_callback *cb);
int prop_send(struct prop *, const void *val, size_t val_len, void *arg);
void prop_table_add(struct prop_table *table);
void sched_run_all(u32 *tick_ct_to_use);
struct prop_table {...};
ayla/libayla/callback.c
ayla/libayla/clock_utils.c
ayla/libayla/conf_access.c
ayla/libayla/crc16.c
ayla/libayla/crc32.c
ayla/libayla/host_event.c
ayla/libayla/host_lib.c
ayla/libayla/host_log.c
ayla/libayla/host_ota.c
ayla/libayla/prop_dp.c
ayla/libayla/props.c
ayla/libayla/sched.c
ayla/libayla/schedeval.c
ayla/libayla/serial_msg.c
ayla/libayla/spi.c
ayla/libayla/spi_ping.c
ayla/libayla/timer.c
ayla/libayla/tlv.c
ayla/libayla/uart.c
ayla/libayla/utf8.c
ayla/libayla/wifi_conf.c
libtarget.aThis platform-dependent library implements the host board API. As you can see by the files below, the default host board is the STM32F303RE Nucleo board. Porting your host application to a different host board means replacing libtarget.a.
arch/stm32/al_intr.c
arch/stm32/stm32.c
arch/stm32/uart_platform_noOS.c
arch/stm32f3/mcu_io.c
arch/stm32f3/spi_platform.c
arch/stm32f3/stm32f3_discovery.c
arch/stm32f3/uart_platform.c
arch/stm32f3/console_platform.c
ext/STM32F30x_StdPeriph_Driver/src/stm32f30x_rcc.c
ext/STM32F30x_StdPeriph_Driver/src/stm32f30x_exti.c
ext/STM32F30x_StdPeriph_Driver/src/stm32f30x_flash.c
ext/STM32F30x_StdPeriph_Driver/src/stm32f30x_gpio.c
ext/STM32F30x_StdPeriph_Driver/src/stm32f30x_misc.c
ext/STM32F30x_StdPeriph_Driver/src/stm32f30x_spi.c
ext/STM32F30x_StdPeriph_Driver/src/stm32f30x_syscfg.c
ext/STM32F30x_StdPeriph_Driver/src/stm32f30x_tim.c
ext/CMSIS/Device/ST/STM32F30x/Source/Templates/system_stm32f30x.c

Set up an environment

This section helps you set up a GNU build environment on VMware/Ubuntu so that you can iteratively modify and build the host application on your computer, and download and run it on the STM32 Nucleo board of your Ayla Dev Kit.

  1. Browse to Download Ubuntu Desktop.
  2. Download Ubuntu 19.04.
  3. Run VMware Fusion, click File > New, and drag ubuntu-19.04-desktop-amd64.iso to the installation screen:



  4. Complete the installation:



  5. In the VM, if prompted, update software, and reboot:



  6. Open a terminal:



  7. sudo apt install git.
  8. sudo apt install screen.
  9. Add your user to the dialout group, and restart:

    $ groups matt
    matt : matt adm cdrom sudo dip plugdev lpadmin sambashare
    $ sudo usermod -a -G dialout matt
    $ groups matt
    matt : matt adm dialout cdrom sudo dip plugdev lpadmin sambashare
    
  10. Inspect the OS environment:

    $ git --version
    git version 2.20.1
    

    $ screen --version
    Screen version 4.06.02 (GNU) 23-Oct-17

    $ python2 --version
    Python 2.7.16

    $ python3 --version
    Python 3.7.3

    $ unzip --version
    caution: both -n and -o specified; ignoring -o
    UnZip 6.00 of 20 April 2009, by Debian. Original by Info-ZIP.

    $ gcc --version
    gcc (Ubuntu 8.3.0-6ubuntu1) 8.3.0
    Copyright (C) 2018 Free Software Foundation, Inc.

    $ make --version
    GNU Make 4.2.1
    Built for x86_64-pc-linux-gnu
    Copyright (C) 1988-2016 Free Software Foundation, Inc.

Add ARM and Ayla

  1. Browse to ARM, and download gcc-arm-none-eabi-8-2018-q4-major-linux.tar.bz2.
  2. Move the file to /home/matt, and extract:
    $ tar xjf gcc-arm-none-eabi-8-2018-q4-major-linux.tar.bz2
    
    You should see the following in /home/matt:
    $ ls -1d gcc*
    gcc-arm-none-eabi-8-2018-q4-major
    gcc-arm-none-eabi-8-2018-q4-major-linux.tar.bz2
    
  3. Install openocd:
    $ sudo apt-get install openocd
    
    It should install in the following location:
    $ ls -1 /usr/bin/openocd
    /usr/bin/openocd
    

    Note the /usr/share/openocd/scripts directory which contains essential configuration files (e.g. board/st_nucleo_f3.cfg) that enable openocd to communicate with your Ayla Dev Kit.

    You may want to run these commands:

    $ which openocd
    /usr/bin/openocd
    
     
    
    
    
    $ openocd --version  
    Open On-Chip Debugger 0.10.0  
    
  4. Download the Ayla Host Library archive file (e.g. Ayla-host-lib-2.0.zip) to /home/matt, and unzip:
    $ unzip Ayla-host-lib-2.0-rc4.zip
    
    You should see this in /home/matt:
    $ ls -1d Ayla*
    Ayla-host-lib-2.0
    Ayla-host-lib-2.0-rc4.zip
    
    If you need to copy the Ayla Host Library archive file from your computer to the VM, you first need to enable sharing:
    1. On the VMware Fusion menu bar, click Virtual Machine > Sharing > Sharing Settings.
    2. Check Enable Shared Folders.
    3. Click the + sign, and add a folder.
    4. Exit the Sharing dialog box.
    5. In a VM terminal, access the shared folder with cd /mnt/hgfs and ls.
  5. Modify your shell environment:
    $ export TOOLCHAIN_DIR=/home/matt/gcc-arm-none-eabi-8-2018-q4-major
    $ export PYTHON=python3
    
  6. Build Ayla components:
    $ cd ~/Ayla-host-lib-2.0
    $ make SHIELD=esp32c3 USE_UART=1
    **NOTE**: The ESP32C3 Ayla Production Agent only supports interfacing with the host via a UART interface.
    
  7. Connect your computer to the STM32 Nucleo board of your Ayla Dev Kit:



  8. Connect to Linux:



    The following notification appears:



  9. Flash build/stm32f3_nucleo/spi/example/app/ledevb/ledevb.img to your Ayla Dev Kit:
    $ make SHIELD=esp32c3 USE_UART=1 download
    

Test the environment

Recall that the default host application includes input and output integer properties, and that when you set input to a value (e.g. 5) the host application sets output to input * input (e.g. 25). Changing this behavior so that the host application sets output to input + input (e.g. 10) provides a simple way to test your build environment:

  1. cd ~/Ayla-host-lib-2.0.
  2. cp example/app/ledevb/demo.c example/app/ledevb/demo.orig.
  3. nano example/app/ledevb/demo.c.
  4. Find the prop_table array:
    static struct prop prop_table[] = {
      ...
      ...
    }
    
  5. Find the input prop structure within the array:
    {"input", ATLV_INT, set_input, prop_send_generic, &input, sizeof(input)},
    
    Note that the Ayla Cloud invokes set_input to set a new value for the input property.
  6. Find the set_input function:
    static void set_input(struct prop *prop, void *arg, void *valp, size_t len)
      ...
      output = i * i;
      ...
    }
    
  7. Change i * i to i + i, and save.
  8. make and make download.
    Press/release the black button on the host board to run the newly downloaded host app.



  9. In Aura, change input to some value (e.g. 4), and verify that output changes to twice the value (e.g. 8).



Tutorials

Below are a set of tutorials that build on the Baseline application.

Baseline application

This example is a simplified version of the default example/app/ledevb/demo.c. As you can see in the listing, it includes only four properties: Blue_button, Green_LED, version, and oem_host_version. Below the listing are instructions for running the example followed by a line-by-line analysis. Subsequent pages in the guide provide a series of examples that augment this baseline example to help you explore additional capabilities.

#include <string.h>
#include <ayla/utypes.h>
#include <ayla/host_lib.h>
#include <arch/board.h>
#include <mcu_io.h>
#include <toolchain/attributes.h>
#include <ayla/ayla_proto_mcu.h>
#include <ayla/props.h>
#include <demo/demo.h>

#define DEMO_SUFFIX ""
#define DEMO_NAME "demo"
#define DEMO_VERSION "2.0"

const char version[] ATTRIB_VERSION = DEMO_NAME DEMO_SUFFIX " " DEMO_VERSION " " BUILD_VERSION;
static char template_version[] = DEMO_NAME DEMO_SUFFIX " 1.9";

static u8 blue_button;

static void set_led(struct prop *prop, void *arg, void *valp, size_t len) {
  u8 val = *(u8 *)valp;
  u32 led = (u32)arg;
  board_led_set(led, val);
}

static int send_led(struct prop *prop, void *arg) {
  u32 led = (u32)prop->arg;
  u8 val = board_led_get(led);
  return prop_send(prop, &val, sizeof(val), arg);
}

static int send_version(struct prop *prop, void *arg) {
  return prop_send(prop, version, strlen(version), arg);
}

static struct prop prop_table[] = {
  {"Blue_button", ATLV_BOOL, NULL, prop_send_generic, &blue_button, sizeof(blue_button)},
  {"Green_LED", ATLV_BOOL, set_led, send_led, (void *)LED1, 1},
  {"version", ATLV_UTF8, NULL, send_version, NULL, 0},
  {"oem_host_version", ATLV_UTF8, NULL, prop_send_generic, template_version, sizeof(template_version) - 1},
};

static struct prop_table demo_prop_table = PROP_TABLE_INIT(prop_table);

static void demo_set_button_state(u32 button, u32 button_value) {
  blue_button = button_value;
  prop_send_req("Blue_button");
}

int main(int argc, char **argv) {
  board_init(argc, argv);
  ayla_host_lib_init();
  board_module_reset();
  demo_factory_reset_handle();
  mcu_button_handler_set(0, demo_set_button_state);
  prop_table_add(&demo_prop_table);
  prop_send_req_to_ads_only("version");
  prop_request_value(NULL);

  for (;;) {
    demo_poll();
  }
}
  • cd ~/Ayla-host-lib-2.0.
  • If necessary, cp example/app/ledevb/demo.c example/app/ledevb/demo.orig.
  • nano example/app/ledevb/demo.c, and replace the contents with the example.
  • make and make download.
  • Press/release the black button on the host board.
  • Verify that the Blue_button and Green_LED properties work.
  • ## Analyze the example ### prop_table The primary Ayla-related purpose of a host application is to define and maintain a prop_table with one entry for each supported property:
    static struct prop prop_table[] = {
      {"Blue_button", ATLV_BOOL, NULL, prop_send_generic, &blue_button, sizeof(blue_button)},
      {"Green_LED", ATLV_BOOL, set_led, send_led, (void *)LED1, 1},
      {"version", ATLV_UTF8, NULL, send_version, NULL, 0},
      {"oem_host_version", ATLV_UTF8, NULL, prop_send_generic, template_version, sizeof(template_version) - 1},
    };
    
    static struct prop_table demo_prop_table = PROP_TABLE_INIT(prop_table);
    
    prop_table_add(&demo_prop_table);
    

    A prop_table is an array of struct prop instances, each containing the name, type, set function pointer, send function pointer, value, and/or other information pertinent to a supported property. To Device properties like Green_LED have both set and send function pointers. The Ayla Cloud calls the set function to, for example, power on/off an LED. The host application utilizes the send function to provide the current state of the property to the Ayla Cloud when, for example, the device comes back online. From Device properties like Blue_button, version, and oem_host_version, which send information to the Ayla Cloud, but do not receive information from the cloud, have send functions, but not set functions. So, for example, Blue_button sends changes in button state to the Ayla Cloud, but does not allow the cloud to change button state.

    The PROP_TABLE_INIT macro transforms a struct prop array into a struct prop_table as required by the prop_table_add function which provides to the Ayla Agent a pointer to the property table.

    These structures and macros are defined in ayla/libayla/include/ayla/props.h.

    Blue_button

    To handle blue button interrupt events, the host application implements demo_set_button_state which sets blue_button to the new value, and then calls prop_send_req to schedule the sending of the Blue_button property value via prop_send_generic.

    static u8 blue_button;
    
    static void demo_set_button_state(u32 button, u32 button_value) {
      blue_button = button_value;
      prop_send_req("Blue_button");
    }
    
    mcu_button_handler_set(0, demo_set_button_state);
    

    During initialization, the host application registers demo_set_button_state with the platform-dependent layer (libtarget.a) by calling mcu_button_handler_set.

    Green_LED

    To handle green LED events from the Ayla Cloud, the host application implements set_led which calls board_led_set, part of the platform-dependent layer in libtarget.a, to power on/off the LED.

    static void set_led(struct prop *prop, void *arg, void *valp, size_t len) {
      u8 val = *(u8 *)valp;
      u32 led = (u32)arg;
      board_led_set(led, val);
    }
    
    static int send_led(struct prop *prop, void *arg) {
      u32 led = (u32)prop->arg;
      u8 val = board_led_get(led);
      return prop_send(prop, &val, sizeof(val), arg);
    }
    

    The host application also implements send_led to determine the current state of an LED, and send the state to the Ayla Cloud, usually at initialization time.

    version

    The version property specifies the host application software version (e.g. demo 2.0 2019-06-06 06:29:07). You do not have to use the constants and macro seen in the code snippet. You can use a string instead.

    ATTRIB_VERSION is defined in toolchain/gcc/include/toolchain/attributes.h.

    BUILD_VERSION is defined in example/libdemo/include/demo/demo.h

    #define DEMO_SUFFIX ""
    #define DEMO_NAME "demo"
    #define DEMO_VERSION "2.0"
    
    const char version[] ATTRIB_VERSION = DEMO_NAME DEMO_SUFFIX " " DEMO_VERSION " " BUILD_VERSION;
    

    Important: The property name "version" does NOT indicate that this property contains the host application software version. Rather, it is the property attribute "Host SW Version" set to TRUE. To see this property attribute, browse to the Ayla Developer Portal, click on the DSN of your device, click on the version property, and note the "Host SW Version" attribute set to TRUE.

    oem_host_version

    The oem_host_version property helps to tell the Ayla Cloud which template to use when instantiating a digital twin for this device. The Ayla Cloud actually uses the OEM ID, OEM Model, and template version when choosing a template for a device.

    #define DEMO_SUFFIX ""
    #define DEMO_NAME "demo"
    
    static char template_version[] = DEMO_NAME DEMO_SUFFIX " 1.9";
    
    static struct prop prop_table[] = {
      {"oem_host_version", ATLV_UTF8, NULL, prop_send_generic, template_version, sizeof(template_version) - 1},
    };
    

    oem_host_version is an "internal reserved property" by name. The Ayla Cloud creates one of these properties for each digital twin.

    main

    int main(int argc, char **argv) {
      board_init(argc, argv);
      ayla_host_lib_init();
      board_module_reset();
      demo_factory_reset_handle();
      mcu_button_handler_set(0, demo_set_button_state);
      prop_table_add(&demo_prop_table);
      prop_send_req_to_ads_only("version");
      prop_request_value(NULL);
    
      for (;;) {
        demo_poll();
      }
    }
    
    Line 51The board_init function initializes the host board which may include initializing timers, interrupts, and serial communication.
    Line 52The ayla_host_lib_init function initializes platform-independent libayla.a which enables communication between the host application and the Ayla Agent.
    Line 53The board_module_reset function sets up a reset line to the Ayla Module, and pulses the line to reset the module.
    Line 54The demo_factory_reset_handle function checks to see if a user has pushed a button on the host board to cause a factory reset and, if so, tells the Ayla Module to reset the host board.
    Line 55The mcu_button_handler_set function tells libtarget.a which function to call for button interrupts.
    Line 56The prop_table_add function provides libayla.a a pointer to the demo_prop_table which includes a pointer to the prop_table array.
    Line 57The prop_send_req_to_ads_only function schedules the sending of the version property value to the Ayla Cloud.
    Line 58The prop_request_value function asks the Ayla Cloud to send all "To Device" property values to the host application.
    Line 61The demo_poll function processes callbacks and timers. It must be called within an infinite loop.

    Console example

    This example shows how to enable serial communication between (1) a terminal on your computer and (2) the host application on your dev kit. With serial communication enabled, you can (a) issue commands to the host app, and (b) view printf messages from the host app, helpful especially during development. In the example, the yellow lines, which implement console functionality, are additions to the Baseline application.

    #include <string.h>
    #include <ayla/utypes.h>
    #include <ayla/host_lib.h>
    #include <arch/board.h>
    #include <mcu_io.h>
    #include <toolchain/attributes.h>
    #include <ayla/ayla_proto_mcu.h>
    #include <ayla/props.h>
    #include <demo/demo.h>
    
    #define DEMO_SUFFIX ""
    #define DEMO_NAME "demo"
    #define DEMO_VERSION "2.0"
    
    const char version[] ATTRIB_VERSION = DEMO_NAME DEMO_SUFFIX " " DEMO_VERSION " " BUILD_VERSION;
    static char template_version[] = DEMO_NAME DEMO_SUFFIX " 1.9";
    
    static u8 blue_button;
    
    static void set_led(struct prop *prop, void *arg, void *valp, size_t len) {
      u8 val = *(u8 *)valp;
      u32 led = (u32)arg;
      board_led_set(led, val);
      demo_log("%s set %s to %u", prop_source_string(prop), prop->name, val);
    }
    
    static int send_led(struct prop *prop, void *arg) {
      u32 led = (u32)prop->arg;
      u8 val = board_led_get(led);
      return prop_send(prop, &val, sizeof(val), arg);
    }
    
    static int send_version(struct prop *prop, void *arg) {
      return prop_send(prop, version, strlen(version), arg);
    }
    
    static struct prop prop_table[] = {
      {"Blue_button", ATLV_BOOL, NULL, prop_send_generic, &blue_button, sizeof(blue_button)},
      {"Green_LED", ATLV_BOOL, set_led, send_led, (void *)LED1, 1},
      {"version", ATLV_UTF8, NULL, send_version, NULL, 0},
      {"oem_host_version", ATLV_UTF8, NULL, prop_send_generic, template_version, sizeof(template_version) - 1},
    };
    
    static struct prop_table demo_prop_table = PROP_TABLE_INIT(prop_table);
    
    static void demo_set_button_state(u32 button, u32 button_value) {
      blue_button = button_value;
      prop_send_req("Blue_button");
    }
    
    int main(int argc, char **argv) {
      board_init(argc, argv);
      ayla_host_lib_init();
    #ifdef DEMO_CONSOLE
      atty_init(console_cli);
    #endif
      board_module_reset();
      demo_factory_reset_handle();
      demo_log("host application version is \"%s\"", version);
      demo_log("Host template version is \"%s\"", template_version);
      demo_log("host library version is \"%s\"", ayla_host_lib_version());
      mcu_button_handler_set(0, demo_set_button_state);
      prop_table_add(&demo_prop_table);
      prop_send_req_to_ads_only("version");
      prop_request_value(NULL);
      demo_log("init completed\n");
    
      for (;;) {
        demo_poll();
      }
    }
    

    Run the example:

    1. cd ~/Ayla-host-lib-2.0.
    2. nano example/app/ledevb/demo.c, and replace the contents with the example.
    3. make and make download.
    4. Open a screen session with screen /dev/ttyACM0 115200 or similar.
    5. Press/release the black button on the host board.
    6. View the output in your screen session:
      demo: host application version is "demo 2.0 2019-06-06 13:05:05"
      demo: Host template version is "demo 1.9"
      demo: host library version is "ayla_host_lib 2.0"
      demo: init completed
      ADS connection DOWN
      ADS connection DOWN
      ADS connection UP
      demo: cloud set Green_LED to 0
      pushed version
      
    7. Terminate the screen session with Ctl-A + k + y.

    Analyze the example:

    Line 54

    DEMO_CONSOLE is set to TRUE by default. You can set it to FALSE on the make command line like this:

    $ touch example/app/ledevb/demo.c
    $ make NO_CONSOLE=1
    
    See Makefile for more details.
    Line 55console_cli is the function in example/libcons/console.c that handles console commands. atty_init initializes serial communication between your computer and the host board. It also initializes libcons.a. It is defined in example/libcons/atty.c.
    Line 24
    Line 59
    Line 60
    Line 61
    Line 66

    demo_log defined in example/libdemo/include/demo/demo.h is a macro that, if DEMO_CONSOLE = TRUE, is replaced with the following:

    printf("demo: " fmt "\n", ##__VA_ARGS__)
    

    Ack example

    This example shows how to report to the Ayla Cloud the status of a property update just received from the Ayla Cloud. The example implements the input and output properties mentioned in Test the environment, but limits permissible input values to between 5 and -5 inclusive, so that the greatest permissible output value is 5 * 5 = 25. In the example, the yellow lines, which implement acknowledgement functionality, are additions to the Baseline application.

    #include <string.h>
    #include <ayla/utypes.h>
    #include <ayla/host_lib.h>
    #include <arch/board.h>
    #include <mcu_io.h>
    #include <toolchain/attributes.h>
    #include <ayla/ayla_proto_mcu.h>
    #include <ayla/props.h>
    #include <demo/demo.h>
    
    #define DEMO_SUFFIX ""
    #define DEMO_NAME "demo"
    #define DEMO_VERSION "2.0"
    
    const char version[] ATTRIB_VERSION = DEMO_NAME DEMO_SUFFIX " " DEMO_VERSION " " BUILD_VERSION;
    static char template_version[] = DEMO_NAME DEMO_SUFFIX " 1.9";
    
    static u8 blue_button;
    static s32 input;
    static s32 output;
    
    enum demo_val_err {VAL_NO_ERR = 0, VAL_BAD_LEN, VAL_OUT_OF_RNG};
    
    static void set_led(struct prop *prop, void *arg, void *valp, size_t len) {
      u8 val = *(u8 *)valp;
      u32 led = (u32)arg;
      board_led_set(led, val);
    }
    
    static int send_led(struct prop *prop, void *arg) {
      u32 led = (u32)prop->arg;
      u8 val = board_led_get(led);
      return prop_send(prop, &val, sizeof(val), arg);
    }
    
    static int send_version(struct prop *prop, void *arg) {
      return prop_send(prop, version, strlen(version), arg);
    }
    
    static void set_input(struct prop *prop, void *arg, void *valp, size_t len) {
      s32 i = *(s32 *)valp;
      if (len != sizeof(s32)) {
        prop->ack.ack_status = 1;
        prop->ack.ack_message = VAL_BAD_LEN;
        return;
      }
      if (i > 5 || i < -5) {
        output = -1;
        prop->ack.ack_status = 1;
        prop->ack.ack_message = VAL_OUT_OF_RNG;
      } else {
        input = i;
        output = i * i;
        prop->ack.ack_status = 0;
        prop->ack.ack_message = VAL_NO_ERR;
      }
      demo_log("proposed %s = %ld", prop->name, (long)i);
      demo_log("%s = %ld", prop->name, (long)input);
      demo_log("output = %ld", (long)output);
      prop_send_req("output");
    }
    
    static struct prop prop_table[] = {
      {"Blue_button", ATLV_BOOL, NULL, prop_send_generic, &blue_button, sizeof(blue_button)},
      {"Green_LED", ATLV_BOOL, set_led, send_led, (void *)LED1, 1},
      {"input", ATLV_INT, set_input, prop_send_generic, &input, sizeof(input)},
      {"output", ATLV_INT, NULL, prop_send_generic, &output, sizeof(output)},
      {"version", ATLV_UTF8, NULL, send_version, NULL, 0},
      {"oem_host_version", ATLV_UTF8, NULL, prop_send_generic, template_version, sizeof(template_version) - 1},
    };
    
    static struct prop_table demo_prop_table = PROP_TABLE_INIT(prop_table);
    
    static void demo_set_button_state(u32 button, u32 button_value) {
      blue_button = button_value;
      prop_send_req("Blue_button");
    }
    
    int main(int argc, char **argv) {
      board_init(argc, argv);
      ayla_host_lib_init();
      atty_init(console_cli);
      board_module_reset();
      demo_factory_reset_handle();
      mcu_button_handler_set(0, demo_set_button_state);
      prop_table_add(&demo_prop_table);
      prop_send_req_to_ads_only("version");
      prop_request_value(NULL);
    
      for (;;) {
        demo_poll();
      }
    }
    

    Run the example:

    1. cd ~/Ayla-host-lib-2.0.
    2. nano example/app/ledevb/demo.c, and replace the contents with the example.
    3. make and make download.
    4. Open a screen session with screen /dev/ttyACM0 115200 or similar.
    5. Press/release the black button on the host board.
    6. View the output in your screen session:

      ADS connection DOWN
      ADS connection DOWN
      ADS connection UP
      demo: cloud set input to 4
      demo: set output to 16
      pushed output
      pushed version
      
    7. Browse to the [Ayla Developer Portal](/system-administration/ayla-developer-portal), click on the input property of your device, check Ack Enabled, and click OK:



    8. In the Ayla Developer Portal, set input to 5:



      5 is a permissible number, so the host app squares it.

    9. Check the serial console:

      demo: proposed input = 5
      demo: input = 5
      demo: output = 25
      pushed output
      
    10. Check the input datapoint tab:



    11. Then, set input to 7:



      7 is not a permissible number, so, after receiving the negative ack from the host app, the cloud resets to the previous value.

    12. Check the serial console:

      demo: proposed input = 7
      demo: input = 5
      demo: output = -1
      pushed output
      
    13. Check the input datapoint tab:

    Metadata example

    This example shows how to include metadata with property value updates. By default, when a host app sends a property value to the Ayla Cloud, the cloud records the new datapoint along with a timestamp. You may, however, want to record additional metadata that provides context to the datapoint such as location, temperature, pressure, customer id, etc. In the example, the yellow lines, which implement metadata functionality, are additions to the Baseline application.

    #include <string.h>
    #include <ayla/utypes.h>
    #include <ayla/host_lib.h>
    #include <arch/board.h>
    #include <mcu_io.h>
    #include <toolchain/attributes.h>
    #include <ayla/ayla_proto_mcu.h>
    #include <ayla/props.h>
    #include <demo/demo.h>
    
    #define DEMO_SUFFIX ""
    #define DEMO_NAME "demo"
    #define DEMO_VERSION "2.0"
    
    const char version[] ATTRIB_VERSION = DEMO_NAME DEMO_SUFFIX " " DEMO_VERSION " " BUILD_VERSION;
    static char template_version[] = DEMO_NAME DEMO_SUFFIX " 1.9";
    
    static u8 blue_button;
    
    static void set_led(struct prop *prop, void *arg, void *valp, size_t len) {
      u8 val = *(u8 *)valp;
      u32 led = (u32)arg;
      board_led_set(led, val);
    }
    
    static int send_led(struct prop *prop, void *arg) {
      u32 led = (u32)prop->arg;
      u8 val = board_led_get(led);
      return prop_send(prop, &val, sizeof(val), arg);
    }
    
    static int send_version(struct prop *prop, void *arg) {
      return prop_send(prop, version, strlen(version), arg);
    }
    
    static int send_prop_with_meta(struct prop *prop, void *arg) {
      struct datapoint_meta meta[DP_META_MAX_ENTRIES + 1];
      int rc;
      memset(&meta, 0, sizeof(meta));
      meta[0].key = "mykey0";
      meta[0].val = "myval0";
      meta[1].key = "mykey1";
      meta[1].val = "myval1";
      rc = prop_validate_meta(meta);
      if (rc < 0) {
        prop->send_mask = 0;
        return rc;
      }
      return prop_send_meta(prop, meta, arg);
    }
    
    static struct prop prop_table[] = {
      {"Blue_button", ATLV_BOOL, NULL, send_prop_with_meta, &blue_button, sizeof(blue_button)},
      {"Green_LED", ATLV_BOOL, set_led, send_led, (void *)LED1, 1},
      {"version", ATLV_UTF8, NULL, send_version, NULL, 0},
      {"oem_host_version", ATLV_UTF8, NULL, prop_send_generic, template_version, sizeof(template_version) - 1},
    };
    
    static struct prop_table demo_prop_table = PROP_TABLE_INIT(prop_table);
    
    static void demo_set_button_state(u32 button, u32 button_value) {
      blue_button = button_value;
      prop_send_req("Blue_button");
    }
    
    int main(int argc, char **argv) {
      board_init(argc, argv);
      ayla_host_lib_init();
      board_module_reset();
      demo_factory_reset_handle();
      mcu_button_handler_set(0, demo_set_button_state);
      prop_table_add(&demo_prop_table);
      prop_send_req_to_ads_only("version");
      prop_request_value(NULL);
    
      for (;;) {
        demo_poll();
      }
    }
    

    Run the example:

    1. cd ~/Ayla-host-lib-2.0.
    2. nano example/app/ledevb/demo.c, and replace the contents with the example.
    3. make and make download.
    4. Press/release the black button on the host board.
    5. Press/release the blue button on the Ayla Shield to send a datapoint (with metadata) to the Ayla Cloud.
    6. Browse to the [Ayla Developer Portal](/system-administration/ayla-developer-portal), click the DSN of your Ayla Dev Kit, click the Blue_button property, click Datapoints, and note the new datapoints with your metadata.

    Schedule example

    This example shows how to implement a schedule property which receives (from the Ayla Cloud) and executes a set of repeatable, user-defined actions between two points of time. In the example, the yellow lines, which implement schedule functionality, are additions to the Baseline application.

    #include <string.h>
    #include <ayla/utypes.h>
    #include <ayla/host_lib.h>
    #include <arch/board.h>
    #include <mcu_io.h>
    #include <toolchain/attributes.h>
    #include <ayla/ayla_proto_mcu.h>
    #include <ayla/props.h>
    #include <demo/demo.h>
    #include <ayla/schedeval.h>
    #include <ayla/sched.h>
    
    #define DEMO_SUFFIX ""
    #define DEMO_NAME "demo"
    #define DEMO_VERSION "2.0"
    
    const char version[] ATTRIB_VERSION = DEMO_NAME DEMO_SUFFIX " " DEMO_VERSION " " BUILD_VERSION;
    static char template_version[] = DEMO_NAME DEMO_SUFFIX " 1.9";
    
    static u8 blue_button;
    
    static void set_led(struct prop *prop, void *arg, void *valp, size_t len) {
      u8 val = *(u8 *)valp;
      u32 led = (u32)arg;
      board_led_set(led, val);
    }
    
    static int send_led(struct prop *prop, void *arg) {
      u32 led = (u32)prop->arg;
      u8 val = board_led_get(led);
      return prop_send(prop, &val, sizeof(val), arg);
    }
    
    static int send_version(struct prop *prop, void *arg) {
      return prop_send(prop, version, strlen(version), arg);
    }
    
    #define DEMO_NSCHED 1
    static struct sched_prop demo_sched[DEMO_NSCHED];
    
    static void demo_sched_set(struct prop *prop, void *arg, void *valp, size_t len) {
      struct sched_prop *sched = (struct sched_prop *)arg;
      if (len > sizeof(sched->tlvs)) {
        demo_log("received schedule %s is too long, %u bytes", prop->name, len);
        len = 0;
      }
      demo_log("%s set %s (%u bytes)", prop_source_string(prop), prop->name, len);
      memcpy(sched->tlvs, valp, len);
      sched->len = len;
      sched_run_all(NULL);
    }
    
    static struct prop prop_table[] = {
      {"Blue_button", ATLV_BOOL, NULL, prop_send_generic, &blue_button, sizeof(blue_button)},
      {"Green_LED", ATLV_BOOL, set_led, send_led, (void *)LED1, 1},
      {"schedule_in", ATLV_SCHED, demo_sched_set, NULL, &demo_sched[0]},
      {"version", ATLV_UTF8, NULL, send_version, NULL, 0},
      {"oem_host_version", ATLV_UTF8, NULL, prop_send_generic, template_version, sizeof(template_version) - 1},
    };
    
    static struct prop_table demo_prop_table = PROP_TABLE_INIT(prop_table);
    
    static void demo_set_button_state(u32 button, u32 button_value) {
      blue_button = button_value;
      prop_send_req("Blue_button");
    }
    
    int main(int argc, char **argv) {
      board_init(argc, argv);
      ayla_host_lib_init();
      atty_init(console_cli);
      board_module_reset();
      demo_factory_reset_handle();
      mcu_button_handler_set(0, demo_set_button_state);
      prop_table_add(&demo_prop_table);
      prop_send_req_to_ads_only("version");
      prop_request_value(NULL);
    
      for (;;) {
        demo_poll();
      }
    }
    

    Run the example:

    1. cd ~/Ayla-host-lib-2.0.
    2. nano example/app/ledevb/demo.c, and replace the contents with the example.
    3. make and make download.
    4. Open a screen session with screen /dev/ttyACM0 115200 or similar.
    5. Press/release the black button on the host board.
    6. View the output in your screen session:

      ADS connection DOWN
      ADS connection DOWN
      ADS connection UP
      pushed version
      demo: cloud set schedule_in (47 bytes)
      
    7. Verify that the Blue_button and Green_LED properties work.
    8. In Aura, tap Schedules:



    9. Tap schedule_in:



    10. Modify Scheduled Actions to target the Green_LED property:



    11. Modify Start Time an End Time, and tap Save Schedule.
    12. Observe the green LED glow and dim.

    Config example

    This example shows how to obtain and display configuration information from the Ayla production module affixed to the Ayla Shield of your dev kit. In the example, the yellow lines, which implement config functionality, are additions to the Baseline application.

    #include <string.h>
    #include <ayla/utypes.h>
    #include <ayla/host_lib.h>
    #include <arch/board.h>
    #include <mcu_io.h>
    #include <toolchain/attributes.h>
    #include <ayla/conf_token.h>
    #include <ayla/conf_access.h>
    #include <ayla/ayla_proto_mcu.h>
    #include <ayla/props.h>
    #include <demo/demo.h>
    
    #define DEMO_SUFFIX ""
    #define DEMO_NAME "demo"
    #define DEMO_VERSION "2.0"
    
    const char version[] ATTRIB_VERSION = DEMO_NAME DEMO_SUFFIX " " DEMO_VERSION " " BUILD_VERSION;
    static char template_version[] = DEMO_NAME DEMO_SUFFIX " 1.9";
    
    static u8 blue_button;
    
    static void set_led(struct prop *prop, void *arg, void *valp, size_t len) {
      u8 val = *(u8 *)valp;
      u32 led = (u32)arg;
      board_led_set(led, val);
    }
    
    static int send_led(struct prop *prop, void *arg) {
      u32 led = (u32)prop->arg;
      u8 val = board_led_get(led);
      return prop_send(prop, &val, sizeof(val), arg);
    }
    
    static int send_version(struct prop *prop, void *arg) {
      return prop_send(prop, version, strlen(version), arg);
    }
    
    static struct prop prop_table[] = {
      {"Blue_button", ATLV_BOOL, NULL, prop_send_generic, &blue_button, sizeof(blue_button)},
      {"Green_LED", ATLV_BOOL, set_led, send_led, (void *)LED1, 1},
      {"version", ATLV_UTF8, NULL, send_version, NULL, 0},
      {"oem_host_version", ATLV_UTF8, NULL, prop_send_generic, template_version, sizeof(template_version) - 1},
    };
    
    static struct prop_table demo_prop_table = PROP_TABLE_INIT(prop_table);
    
    static void demo_set_button_state(u32 button, u32 button_value) {
      blue_button = button_value;
      prop_send_req("Blue_button");
    }
    
    int main(int argc, char **argv) {
      board_init(argc, argv);
      ayla_host_lib_init();
      atty_init(console_cli);
      board_module_reset();
      demo_factory_reset_handle();
      conf_poll_start();
      mcu_button_handler_set(0, demo_set_button_state);
      prop_table_add(&demo_prop_table);
      prop_send_req_to_ads_only("version");
      prop_request_value(NULL);
    
      for (;;) {
        demo_poll();
      }
    }
    

    Run the example:

    1. cd ~/Ayla-host-lib-2.0.
    2. nano example/app/ledevb/demo.c, and replace the contents with the example.
    3. make and make download.
    4. Open a screen session with screen /dev/ttyACM0 115200 or similar.
    5. Press/release the black button on the host board.
    6. View the output in your screen session:

      ADS connection DOWN
      conf_dsn_rx: dsn AC000W000340322
      conf_model_rx: model AY001MTC1
      ADS connection DOWN
      ADS connection UP
      pushed version
      

    Analyze the example:

    conf_poll_start defined in ayla/libayla/conf_access.c eventually invokes conf_poll:

    static int conf_poll(void) {
      const enum conf_token devid_tokens[] = { CT_sys, CT_dev_id };
      const enum conf_token model_tokens[] = { CT_sys, CT_model };
      ...
      if (conf_dsn[0] == '\0') {
        if (conf_read(devid_tokens, 2, conf_dsn_rx)) {
          return -1;
        }
      }
      if (conf_model[0] == '\0') {
        if (conf_read(model_tokens, 2, conf_model_rx)) {
          return -1;
        }
      }
      return 0;
    }
    

    conf_dsn_rx invokes host_log to write the DSN to the serial port for display by the serial terminal on your computer:

    static void conf_dsn_rx(void *buf, size_t len) {
      struct ayla_tlv *tlv;
    
     
    
    
    
      tlv = tlv_get(ATLV_UTF8, buf, len);  
      if (!tlv) {  
        return;  
      }  
      if (tlv->len >= sizeof(conf_dsn)) {  
        return;  
      }  
      memcpy(conf_dsn, tlv + 1, tlv->len);  
      conf_dsn[tlv->len] = '\\0';  
      host_log("conf_dsn_rx: dsn %s", conf_dsn);  
    }  
    

    conf_model_rx also invokes host_log:

    static void conf_model_rx(void *buf, size_t len) {
      struct ayla_tlv *tlv;
    
     
    
    
    
      tlv = tlv_get(ATLV_UTF8, buf, len);  
      if (!tlv) {  
        return;  
      }  
      if (tlv->len >= sizeof(conf_model)) {  
        return;  
      }  
      memcpy(conf_model, tlv + 1, tlv->len);  
      conf_model[tlv->len] = '\\0';  
      host_log("conf_model_rx: model %s", conf_model);  
    }  
    

    Event register example

    This example shows how to register callbacks using host_event_register to receive notifications about events occurring on the Ayla production module. These events include when the module resets, and when the module enters standby mode. In the example, the yellow lines, which implement event functionality, are additions to the Baseline application. To learn how to cause an event on the Ayla production module using host_event_notify, see the Event notify example.

    #include <string.h>
    #include <ayla/utypes.h>
    #include <ayla/host_lib.h>
    #include <ayla/host_event.h>
    #include <arch/board.h>
    #include <mcu_io.h>
    #include <toolchain/attributes.h>
    #include <ayla/ayla_proto_mcu.h>
    #include <ayla/props.h>
    #include <demo/demo.h>
    
    #define DEMO_SUFFIX ""
    #define DEMO_NAME "demo"
    #define DEMO_VERSION "2.0"
    
    const char version[] ATTRIB_VERSION = DEMO_NAME DEMO_SUFFIX " " DEMO_VERSION " " BUILD_VERSION;
    static char template_version[] = DEMO_NAME DEMO_SUFFIX " 1.9";
    
    static u8 blue_button;
    
    static void set_led(struct prop *prop, void *arg, void *valp, size_t len) {
      u8 val = *(u8 *)valp;
      u32 led = (u32)arg;
      board_led_set(led, val);
    }
    
    static int send_led(struct prop *prop, void *arg) {
      u32 led = (u32)prop->arg;
      u8 val = board_led_get(led);
      return prop_send(prop, &val, sizeof(val), arg);
    }
    
    static int send_version(struct prop *prop, void *arg) {
      return prop_send(prop, version, strlen(version), arg);
    }
    
    static struct prop prop_table[] = {
      {"Blue_button", ATLV_BOOL, NULL, prop_send_generic, &blue_button, sizeof(blue_button)},
      {"Green_LED", ATLV_BOOL, set_led, send_led, (void *)LED1, 1},
      {"version", ATLV_UTF8, NULL, send_version, NULL, 0},
      {"oem_host_version", ATLV_UTF8, NULL, prop_send_generic, template_version, sizeof(template_version) - 1},
    };
    
    static struct prop_table demo_prop_table = PROP_TABLE_INIT(prop_table);
    
    static void demo_set_button_state(u32 button, u32 button_value) {
      blue_button = button_value;
      prop_send_req("Blue_button");
    }
    
    static void demo_event_cb(enum host_event event, void *data, size_t len) {
      switch (event) {
        case HEV_RESET:
        demo_log("Module was reset.\n");
        break;
    
        default:
        break;
      }
    }
    
    static struct host_event_callback demo_event_callback = HOST_EVENT_INIT_HANDLER(demo_event_cb);
    
    int main(int argc, char **argv) {
      board_init(argc, argv);
      ayla_host_lib_init();
      atty_init(console_cli);
      board_module_reset();
      demo_factory_reset_handle();
      host_event_register(&demo_event_callback);
      mcu_button_handler_set(0, demo_set_button_state);
      prop_table_add(&demo_prop_table);
      prop_send_req_to_ads_only("version");
      prop_request_value(NULL);
    
      for (;;) {
        demo_poll();
      }
    }
    

    Run the example:

    1. cd ~/Ayla-host-lib-2.0.
    2. nano example/app/ledevb/demo.c, and replace the contents with the example.
    3. make and make download.
    4. Open a screen session with screen /dev/ttyACM0 115200 or similar.
    5. Press/release the black button on the host board.
    6. View the output in your screen session:

      ADS connection DOWN
      demo: Module was reset.
      ADS connection DOWN
      ADS connection UP
      pushed version
      

    Analyze the example:

    Events are defined in ayla/libayla/include/ayla/host_event.h:

    enum host_event {
      HEV_NONE = 0,           /* reserved */
      HEV_RESET,              /* module has been reset */
      HEV_STANDBY,            /* module entered standby */
      HEV_WIFI_STATUS,        /* module sent Wi-Fi connection status */
      HEV_WIFI_STATUS_FINAL,  /* module sent Wi-Fi final connection status */
      HEV_REG_INFO,           /* module sent registration info */
      HEV_WAKEUP,             /* module should be woken after standby */
      HEV_FEATURES_SENT,      /* host has sent features to module */
      HEV_TIME_UPDATED,       /* time information updated */
      HEV_PROP_ERROR,         /* property error received */
      HEV_PROP_NOTIFY,        /* property or cmd pending during file xfer */
      _HEV_LIMIT              /* reserved - no trailing comma for Keil */
    };
    

    Event notify example

    This example shows how to cause an event on the Ayla production module using host_event_notify. Specifically, the example shows you how to wake up the module from standby mode. In the example, the yellow lines, which implement event functionality, are additions to the Baseline application. To learn how to register for event notification using host_event_register, see the Event register example.

    #include <string.h>
    #include <ayla/utypes.h>
    #include <ayla/host_lib.h>
    #include <ayla/host_event.h>
    #include <arch/board.h>
    #include <mcu_io.h>
    #include <toolchain/attributes.h>
    #include <ayla/ayla_proto_mcu.h>
    #include <ayla/props.h>
    #include <demo/demo.h>
    
    #define DEMO_SUFFIX ""
    #define DEMO_NAME "demo"
    #define DEMO_VERSION "2.0"
    
    const char version[] ATTRIB_VERSION = DEMO_NAME DEMO_SUFFIX " " DEMO_VERSION " " BUILD_VERSION;
    static char template_version[] = DEMO_NAME DEMO_SUFFIX " 1.9";
    
    static u8 blue_button;
    
    static void set_led(struct prop *prop, void *arg, void *valp, size_t len) {
      u8 val = *(u8 *)valp;
      u32 led = (u32)arg;
      board_led_set(led, val);
    }
    
    static int send_led(struct prop *prop, void *arg) {
      u32 led = (u32)prop->arg;
      u8 val = board_led_get(led);
      return prop_send(prop, &val, sizeof(val), arg);
    }
    
    static int send_version(struct prop *prop, void *arg) {
      return prop_send(prop, version, strlen(version), arg);
    }
    
    static struct prop prop_table[] = {
      {"Blue_button", ATLV_BOOL, NULL, prop_send_generic, &blue_button, sizeof(blue_button)},
      {"Green_LED", ATLV_BOOL, set_led, send_led, (void *)LED1, 1},
      {"version", ATLV_UTF8, NULL, send_version, NULL, 0},
      {"oem_host_version", ATLV_UTF8, NULL, prop_send_generic, template_version, sizeof(template_version) - 1},
    };
    
    static struct prop_table demo_prop_table = PROP_TABLE_INIT(prop_table);
    
    static void demo_set_button_state(u32 button, u32 button_value) {
      blue_button = button_value;
      prop_send_req("Blue_button");
      if (button_value) {
        host_event_notify(HEV_WAKEUP, NULL, 0);
      }
    }
    
    int main(int argc, char **argv) {
      board_init(argc, argv);
      ayla_host_lib_init();
      atty_init(console_cli);
      board_module_reset();
      demo_factory_reset_handle();
      mcu_button_handler_set(0, demo_set_button_state);
      prop_table_add(&demo_prop_table);
      demo_power_mgmt_init();
      prop_send_req_to_ads_only("version");
      prop_request_value(NULL);
    
      for (;;) {
        demo_poll();
      }
    }
    

    Run the example:

    1. cd ~/Ayla-host-lib-2.0.
    2. nano example/app/ledevb/demo.c, and replace the contents with the example.
    3. make and make download.
    4. Open a screen session with screen /dev/ttyACM0 115200 or similar.
    5. Press/release the black button on the host board.
    6. View the output in your screen session:

      ADS connection DOWN
      demo: module reset event
      demo: power mode rx 50
      conf_dsn_rx: dsn AC000W000340322
      conf_model_rx: model AY001MTC1
      ADS connection DOWN
      ADS connection UP
      pushed version
      demo: power timeout - staying up
      
    7. Push Blue_button, and view the output in your screen session:

      demo: module wakeup event - reset not needed
      pushed Blue_button
      pushed Blue_button
      demo: power timeout - staying up
      

    New property example

    The purpose of this example is to show how to add a property to a host application and to the corresponding digital twin in the Ayla Cloud. Specifically, this example shows how to add two string properties, str_in and str_out. The first is a to device property, and the second is a from device. The host application receives a str_in property value update, transforms the string to uppercase, and sends the transformed string back to the cloud as str_out. In the example, the yellow lines, which implement the new properties, are additions to the Baseline application.

    #include <string.h>
    #include <ctype.h>
    #include <ayla/utypes.h>
    #include <ayla/host_lib.h>
    #include <arch/board.h>
    #include <mcu_io.h>
    #include <toolchain/attributes.h>
    #include <ayla/ayla_proto_mcu.h>
    #include <ayla/props.h>
    #include <demo/demo.h>
    
    #define DEMO_SUFFIX ""
    #define DEMO_NAME "demo"
    #define DEMO_VERSION "2.0"
    
    const char version[] ATTRIB_VERSION = DEMO_NAME DEMO_SUFFIX " " DEMO_VERSION " " BUILD_VERSION;
    static char template_version[] = DEMO_NAME DEMO_SUFFIX " 1.9";
    
    static u8 blue_button;
    static char str_in_buf[TLV_MAX_STR_LEN + 1];
    static char str_out_buf[TLV_MAX_STR_LEN + 1];
    
    static void set_led(struct prop *prop, void *arg, void *valp, size_t len) {
      u8 val = *(u8 *)valp;
      u32 led = (u32)arg;
      board_led_set(led, val);
    }
    
    static int send_led(struct prop *prop, void *arg) {
      u32 led = (u32)prop->arg;
      u8 val = board_led_get(led);
      return prop_send(prop, &val, sizeof(val), arg);
    }
    
    static int send_version(struct prop *prop, void *arg) {
      return prop_send(prop, version, strlen(version), arg);
    }
    
    static void set_str_in(struct prop *prop, void *arg, void *valp, size_t len) {
      if (len >= sizeof(str_in_buf)) {
        len = sizeof(str_in_buf) - 1;
      }
      memcpy(str_in_buf, valp, len);
      str_in_buf[len] = '\0';
      for(int i=0; i<len; i++){
        str_out_buf[i] = toupper(str_in_buf[i]);
      }
      str_out_buf[len] = '\0';
      demo_log("str_in = %s", str_in_buf);
      demo_log("str_out = %s", str_out_buf);
      prop_send_req("str_out");
    }
    
    static struct prop prop_table[] = {
      {"Blue_button", ATLV_BOOL, NULL, prop_send_generic, &blue_button, sizeof(blue_button)},
      {"Green_LED", ATLV_BOOL, set_led, send_led, (void *)LED1, 1},
      {"str_in", ATLV_UTF8, set_str_in, prop_send_generic, str_in_buf, 0},
      {"str_out", ATLV_UTF8, NULL, prop_send_generic, str_out_buf, 0},
      {"version", ATLV_UTF8, NULL, send_version, NULL, 0},
      {"oem_host_version", ATLV_UTF8, NULL, prop_send_generic, template_version, sizeof(template_version) - 1},
    };
    
    static struct prop_table demo_prop_table = PROP_TABLE_INIT(prop_table);
    
    static void demo_set_button_state(u32 button, u32 button_value) {
      blue_button = button_value;
      prop_send_req("Blue_button");
    }
    
    int main(int argc, char **argv) {
      board_init(argc, argv);
      ayla_host_lib_init();
      atty_init(console_cli);
      board_module_reset();
      demo_factory_reset_handle();
      mcu_button_handler_set(0, demo_set_button_state);
      prop_table_add(&demo_prop_table);
      prop_send_req_to_ads_only("version");
      prop_request_value(NULL);
    
      for (;;) {
        demo_poll();
      }
    }
    

    Run the example:

    1. Browse to the [Ayla Developer Portal](https://ayla.readme.io/docs/ayla-developer-portal), and click on the DSN of your device.
    2. Click Add.
    3. Add a str_in property to the digital twin by filling in the form, and clicking OK.



    4. Click to update, and set str_in to a known value (e.g. "surprise").



    5. Add a str_out (from device) property.



    6. In a terminal, cd ~/Ayla-host-lib-2.0.
    7. nano example/app/ledevb/demo.c, and replace the contents with the example.
    8. make and make download.
    9. Open a screen session with screen /dev/ttyACM0 115200 or similar.
    10. Press/release the black button on the host board.
    11. View the output in your screen session:

      ADS connection DOWN
      ADS connection DOWN
      ADS connection UP
      demo: str_in = surprise
      demo: str_out = SURPRISE
      pushed str_out
      pushed version
      

    Appendix

    UART mode:

    $ make SHIELD=esp32c3 USE_UART=1
    

    Ayla Shield Schematic

    Click Ayla Shield Schematic.