Ayla Development Kit
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:
-
Connect your mobile device to a 2.4GHz Wi-Fi LAN.
-
On your mobile device, get and install the "Ayla Aura Mobile App" from the App Store or Google Play.
-
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. -
Tap "+" to add a device:
-
Tap Ayla Dev Kit:
-
Enter the same Wi-Fi credentials as those used by your mobile device, and tap Continue:
-
Take your Ayla Dev Kit out of the box.
-
Plug the small end of the cable into the STM32 Nucleo board:
-
Plug the large end into a USB outlet, tap continue, and then tap Join:
-
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
-
Tap the Blue_LED property slider:
The Blue LED on the dev kit illuminates. Tapping the slider sends an update to the device.
-
Tap the Blue_LED slider On/Off several times to generate a history of values.
-
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. -
Tap the Green_LED property slider:
The Green LED on the dev kit illuminates. Tapping this slider also sends an update *to the device*. -
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
- Tap the white space to the right of the cmd property:
- Enter a string like
community
, and tap Update Value.
Setting the cmd property sends a string value *to the device*.
- View the log property:
The host app (on the device) setslog = cmd
, and sends the string *from the device*.
- 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
- Tap the value to the right of the input property:
A dialog box appears. - Enter an integer like
5
, and tap Update Value.
Setting the input property sends an integer value to the device. - View the output property:
The host app (on the device) setsoutput = input * input
, and sends the integer from the device.
Decimal properties
- Tap the value to the right of the decimal_in property:
A dialog box appears. - Enter a decimal like
2.71
, and tap Update Value.
Setting the decimalin property sends a decimal value _to the device. - View the decimalout property:
The host app (on the device) setsdecimal_out = decimal_in
, and sends the decimal _from the device.
File properties
- In the Ayla Developer Portal, on the Device Menu, click the Properties tab to display the "stream" properties:
- 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"...
- In the Display Name column, click the stream_up property.
- Click Download, and download the generated file to your computer.
- Open the file with a text editor to verify the pattern.
- In the Current Value column of the stream_down row, click click to update.
- 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.
- Ensure that the Blue_LED property is off.
- Ensure that the time zone on the dev kit is set appropriately by clicking the Gear, and then Time Zone.
- Tap the Schedules button on the Device screen.
The Schedules screen appears with one pre-made schedule called schedule_in.
- Tap schedule_in to display the Edit Schedule screen.
- Scroll to Schedule Actions:
Note that this schedule sets Blue_LED to 1 at start date/time, and to 0 at end date/time. - Scroll to Start Time, and set the time to a few minutes from now.
- Scroll to End Time, and set the time to a minute after Start Time.
- Scroll to Active, and activate the schedule:
- Tap Save Schedule at the bottom of the screen.
- 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
- Tap "+".
- Tap "Property notification".
- Configure the following fields:
Field Value Notification Name Green LED Changed Notification Message The Green LED changed. Condition When Green_LED has Changed. Send push notification to this device ✓
- Tap Save Notifications.
- Turn on/off Green_LED. See a push notification similar to the following:
Wait a few seconds before generating the next push notification. - Uncheck Send push ..., and save again.
Device notifications
- Tap "+".
- Tap "Device notification".
- Configure the following fields:
Field Value Notification Name Ayla Dev Kit Offline Event on_connection_lost Threshhold 300 (seconds) Notification Message The Ayla Dev Kit is offline. Send push notification to this device ✓
- Tap Save Notifications.
- Disconnect the Ayla Dev Kit, and wait for a few minutes. See a push notification similar to the following:
- 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
- Tap Share Device at the bottom of the Device screen:
- Enter the email address for an existing Ayla user account:
- Choose capabilities:
Note that Default is the same as Read Only. - Optionally, choose a start and end date to define an active duration. Initially, leave this blank.
- Tap Create Share:
You will see the following message:
- Tap Menu Menu > Shares:
You will see the device under "Devices You Own" on the Shared Devices list:
- 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:
- Factory reset your Ayla Dev Kit via Aura (see Aura Factory Reset below).
- Connect your mobile device to the new LAN.
- 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.
Component | Description and Source Files |
---|---|
demo.c | This 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.a | These 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.a | This 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.a | This 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.a | This 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.
- Browse to Download Ubuntu Desktop.
- Download
Ubuntu 19.04
. - Run VMware Fusion, click
File > New
, and dragubuntu-19.04-desktop-amd64.iso
to the installation screen:
- Complete the installation:
- In the VM, if prompted, update software, and reboot:
- Open a terminal:
sudo apt install git
.sudo apt install screen
.- 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
- 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
- Browse to ARM, and download
gcc-arm-none-eabi-8-2018-q4-major-linux.tar.bz2
. - 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
- 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
- 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:- On the VMware Fusion menu bar, click
Virtual Machine > Sharing > Sharing Settings
. - Check
Enable Shared Folders
. - Click the
+
sign, and add a folder. - Exit the Sharing dialog box.
- In a VM terminal, access the shared folder with
cd /mnt/hgfs
andls
.
- On the VMware Fusion menu bar, click
- Modify your shell environment:
$ export TOOLCHAIN_DIR=/home/matt/gcc-arm-none-eabi-8-2018-q4-major $ export PYTHON=python3
- Build Ayla components:
$ cd ~/Ayla-host-lib-2.0 $ make
- Connect your computer to the STM32 Nucleo board of your Ayla Dev Kit:
- Connect to Linux:
The following notification appears:
- Flash
build/stm32f3_nucleo/spi/example/app/ledevb/ledevb.img
to your Ayla Dev Kit:$ make 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:
cd ~/Ayla-host-lib-2.0
.cp example/app/ledevb/demo.c example/app/ledevb/demo.orig
.nano example/app/ledevb/demo.c
.- Find the
prop_table
array:static struct prop prop_table[] = { ... ... }
- Find the
input
prop structure within the array:{"input", ATLV_INT, set_input, prop_send_generic, &input, sizeof(input)},
Note that the Ayla Cloud invokesset_input
to set a new value for theinput
property. - Find the
set_input
function:static void set_input(struct prop *prop, void *arg, void *valp, size_t len) ... output = i * i; ... }
- Change
i * i
toi + i
, and save. make
andmake download
.
Press/release the black button on the host board to run the newly downloaded host app.
- In Aura, change
input
to some value (e.g.4
), and verify thatoutput
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
.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
.
Blue_button
and Green_LED
properties work.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 51 | The board_init function initializes the host board which may include initializing timers, interrupts, and serial communication. |
Line 52 | The ayla_host_lib_init function initializes platform-independent libayla.a which enables communication between the host application and the Ayla Agent. |
Line 53 | The board_module_reset function sets up a reset line to the Ayla Module, and pulses the line to reset the module. |
Line 54 | The 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 55 | The mcu_button_handler_set function tells libtarget.a which function to call for button interrupts. |
Line 56 | The prop_table_add function provides libayla.a a pointer to the demo_prop_table which includes a pointer to the prop_table array. |
Line 57 | The prop_send_req_to_ads_only function schedules the sending of the version property value to the Ayla Cloud. |
Line 58 | The prop_request_value function asks the Ayla Cloud to send all "To Device" property values to the host application. |
Line 61 | The 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:
cd ~/Ayla-host-lib-2.0
.nano example/app/ledevb/demo.c
, and replace the contents with the example.make
andmake download
.- Open a screen session with
screen /dev/ttyACM0 115200
or similar. - Press/release the black button on the host board.
- 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
- Terminate the screen session with
Ctl-A + k + y
.
Analyze the example:
Line 54 |
$ touch example/app/ledevb/demo.c $ make NO_CONSOLE=1See Makefile for more details.
|
Line 55 | console_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 |
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:
cd ~/Ayla-host-lib-2.0
.nano example/app/ledevb/demo.c
, and replace the contents with the example.make
andmake download
.- Open a screen session with
screen /dev/ttyACM0 115200
or similar. - Press/release the black button on the host board.
- 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
- Browse to the [Ayla Developer Portal](/system-administration/ayla-developer-portal), click on the
input
property of your device, checkAck Enabled
, and click OK:
- In the Ayla Developer Portal, set
input
to5
:
5
is a permissible number, so the host app squares it.
- Check the serial console:
demo: proposed input = 5 demo: input = 5 demo: output = 25 pushed output
- Check the
input
datapoint tab:
- Then, set
input
to7
:
7
is not a permissible number, so, after receiving the negative ack from the host app, the cloud resets to the previous value.
- Check the serial console:
demo: proposed input = 7 demo: input = 5 demo: output = -1 pushed output
- 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:
cd ~/Ayla-host-lib-2.0
.nano example/app/ledevb/demo.c
, and replace the contents with the example.make
andmake download
.- Press/release the black button on the host board.
- Press/release the blue button on the Ayla Shield to send a datapoint (with metadata) to the Ayla Cloud.
- 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:
cd ~/Ayla-host-lib-2.0
.nano example/app/ledevb/demo.c
, and replace the contents with the example.make
andmake download
.- Open a screen session with
screen /dev/ttyACM0 115200
or similar. - Press/release the black button on the host board.
- 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)
- Verify that the
Blue_button
andGreen_LED
properties work. - In Aura, tap Schedules:
- Tap
schedule_in
:
- Modify Scheduled Actions to target the Green_LED property:
- Modify Start Time an End Time, and tap Save Schedule.
- 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:
cd ~/Ayla-host-lib-2.0
.nano example/app/ledevb/demo.c
, and replace the contents with the example.make
andmake download
.- Open a screen session with
screen /dev/ttyACM0 115200
or similar. - Press/release the black button on the host board.
- 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:
cd ~/Ayla-host-lib-2.0
.nano example/app/ledevb/demo.c
, and replace the contents with the example.make
andmake download
.- Open a screen session with
screen /dev/ttyACM0 115200
or similar. - Press/release the black button on the host board.
- 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:
cd ~/Ayla-host-lib-2.0
.nano example/app/ledevb/demo.c
, and replace the contents with the example.make
andmake download
.- Open a screen session with
screen /dev/ttyACM0 115200
or similar. - Press/release the black button on the host board.
- 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
- 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:
- Browse to the [Ayla Developer Portal](https://ayla.readme.io/docs/ayla-developer-portal), and click on the DSN of your device.
- Click Add.
- Add a
str_in
property to the digital twin by filling in the form, and clicking OK.
Click to update
, and setstr_in
to a known value (e.g. "surprise").
- Add a
str_out
(from device) property.
- In a terminal,
cd ~/Ayla-host-lib-2.0
. nano example/app/ledevb/demo.c
, and replace the contents with the example.make
andmake download
.- Open a screen session with
screen /dev/ttyACM0 115200
or similar. - Press/release the black button on the host board.
- 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
Serial mode
Serial communication between the Ayla Shield and the STM32 board can be SPI or UART. See the diagram:
You specify SPI or UART mode when you build your host application. SPI mode is the default:
$ make
UART mode requires the following:
$ make USE_UART=1
The choice between SPI and UART depends on your choice of MCU. The STM32 Nucleo board of the Ayla Dev Kit supports both.
Ayla Shield Schematic
Click Ayla Shield Schematic.
Configuration
To configure your Ayla Dev Kit via the command line, see Ayla Module CLI Specifications and Module / MCU Interface. An Ayla Development Kit has three categories of configuration parameters: Factory (f), Startup (s), and Running (r).
Configuration of a dev kit that has just been reset
f log/mod/1/mask = 15 = 0xf f log/mod/2/mask = 15 = 0xf f log/mod/3/mask = 15 = 0xf f log/mod/4/mask = 15 = 0xf f log/mod/5/mask = 15 = 0xf f log/mod/6/mask = 15 = 0xf f log/mod/7/mask = 15 = 0xf f log/mod/8/mask = 15 = 0xf f log/mod/9/mask = 15 = 0xf f log/mod/10/mask = 15 = 0xf f log/mod/11/mask = 15 = 0xf f log/mod/12/mask = 15 = 0xf f log/client/enable = 1 = 0x1 f wifi/mac_addr = len 6 00 00 00 00 00 00 f wifi/scan/save_on_ap_connect = 0 = 0x0 f wifi/scan/save_on_server_connect = 1 = 0x1 f sys/reset = 1 = 0x1 f sys/timezone_valid = 0 = 0x0 f sys/timezone = 0 = 0x0 f sys/dst_active = 0 = 0x0 f sys/dst_change = 0 = 0x0 f sys/dst_valid = 0 = 0x0 f sys/host = 124 = 0x7c f client/lan/enable = 0 = 0x0 f client/server/default = 0 = 0x0 f client/poll_interval = 300 = 0x12c f client/ssl/enable = 1 = 0x1 f power/mode = 80 = 0x50 f power/awake_time = 10 = 0xa f power/standby_powered = 300 = 0x12c f power/unconf_powered = 600 = 0x258 f oem/complete = 0 = 0x0 f metric/client/client/enable = 0 = 0x0 f metric/client/client/poll_interval = 50 = 0x32 f metric/client/client/count = 10 = 0xa f metric/client/http/enable = 0 = 0x0 f metric/client/http/poll_interval = 50 = 0x32 f metric/client/http/count = 10 = 0xa f metric/client/ssl/enable = 0 = 0x0 f metric/client/ssl/poll_interval = 50 = 0x32 f metric/client/ssl/count = 10 = 0xa f metric/client/tcp/enable = 0 = 0x0 f metric/client/tcp/poll_interval = 50 = 0x32 f metric/client/tcp/count = 10 = 0xa f locale/default = 0 = 0x0 f gpio/enable = 0 = 0x0 f gpio/status/wifi = 0 = 0x0 f gpio/status/server = 0 = 0x0 f gpio/status/setup_mode = 0 = 0x0 f gpio/status/ready = 11 = 0xb f gpio/status/link = 1 = 0x1 f gpio/status/intr = 12 = 0xc f gpio/n/0/mode = 0 = 0x0 f gpio/n/1/mode = 75 = 0x4b f gpio/n/2/mode = 0 = 0x0 f gpio/n/3/mode = 0 = 0x0 f gpio/n/4/mode = 0 = 0x0 f gpio/n/5/mode = 0 = 0x0 f gpio/n/6/mode = 0 = 0x0 f gpio/n/7/mode = 0 = 0x0 f gpio/n/11/mode = 75 = 0x4b f gpio/n/12/mode = 75 = 0x4b f gpio/n/18/mode = 0 = 0x0 f gpio/n/29/mode = 0 = 0x0 f gpio/n/30/mode = 0 = 0x0 f gpio/n/31/mode = 0 = 0x0 f gpio/n/45/mode = 0 = 0x0 f wifi/ant = 1 = 0x1 f wifi/enable = 1 = 0x1 f wifi/profile/10/security = 40 = 0x28 f wifi/profile/10/key = "" f wifi/profile/10/enable = 1 = 0x1 f sys/mfg_mode = 0 = 0x0 f client/enable = 1 = 0x1 f log/mod/13/mask = 15 = 0xf f eth/enable = 0 = 0x0 f eth/mac_addr = len 6 00 00 00 00 00 00 f eth/speed = 0 = 0x0 f wifi/power = 31 = 0x1f f wifi/setup_ios_app = "iMDA" f wifi/setup_mode/enable = 0 = 0x0 f wifi/setup_mode/key = (set) f wifi/setup_mode/id = "" f wifi/profile/10/ssid = "Ayla-DevKit" f sys/setup_mode = 0 = 0x0 f sys/setup_mode/key = len 20 f3 13 33 ff 94 79 2c 30 f6 c7 77 f client/server/region = "" f oem/oem = "0dfc7900" f oem/model = "AylaShield" f oem/key = len 256 bf 76 c7 16 cb 31 50 8d 7e 17 3c f oem/version = "demo_dp 1.7" f server/security/enable = 1 = 0x1 f gpio/status/reg = 20 = 0x14 f gpio/status/WPS = 0 = 0x0 f gpio/status/snapshot = 0 = 0x0 f gpio/status/clock = 0 = 0x0 f gpio/status/data = 0 = 0x0 f gpio/status/reset = 0 = 0x0 f gpio/status/test = 0 = 0x0 f gpio/status/ap_mode/setup_mode = 0 = 0x0 f gpio/n/15/mode = 81 = 0x51 f gpio/n/19/mode = 0 = 0x0 f gpio/n/20/mode = 81 = 0x51 types: f = factory, s = startup, r = running
Configuration of a dev kit that has just been connected to the Ayla Cloud
f log/mod/1/mask = 15 = 0xf f log/mod/2/mask = 15 = 0xf f log/mod/3/mask = 15 = 0xf f log/mod/4/mask = 15 = 0xf f log/mod/5/mask = 15 = 0xf f log/mod/6/mask = 15 = 0xf f log/mod/7/mask = 15 = 0xf f log/mod/8/mask = 15 = 0xf f log/mod/9/mask = 15 = 0xf f log/mod/10/mask = 15 = 0xf f log/mod/11/mask = 15 = 0xf f log/mod/12/mask = 15 = 0xf f log/client/enable = 1 = 0x1 f wifi/mac_addr = len 6 00 00 00 00 00 00 f wifi/scan/save_on_ap_connect = 0 = 0x0 f wifi/scan/save_on_server_connect = 1 = 0x1 f sys/host = 124 = 0x7c f client/server/default = 0 = 0x0 f client/poll_interval = 300 = 0x12c f client/ssl/enable = 1 = 0x1 f power/mode = 80 = 0x50 f power/awake_time = 10 = 0xa f power/standby_powered = 300 = 0x12c f power/unconf_powered = 600 = 0x258 f oem/complete = 0 = 0x0 f metric/client/client/enable = 0 = 0x0 f metric/client/client/poll_interval = 50 = 0x32 f metric/client/client/count = 10 = 0xa f metric/client/http/enable = 0 = 0x0 f metric/client/http/poll_interval = 50 = 0x32 f metric/client/http/count = 10 = 0xa f metric/client/ssl/enable = 0 = 0x0 f metric/client/ssl/poll_interval = 50 = 0x32 f metric/client/ssl/count = 10 = 0xa f metric/client/tcp/enable = 0 = 0x0 f metric/client/tcp/poll_interval = 50 = 0x32 f metric/client/tcp/count = 10 = 0xa f locale/default = 0 = 0x0 f gpio/enable = 0 = 0x0 f gpio/status/wifi = 0 = 0x0 f gpio/status/server = 0 = 0x0 f gpio/status/setup_mode = 0 = 0x0 f gpio/status/ready = 11 = 0xb f gpio/status/link = 1 = 0x1 f gpio/status/intr = 12 = 0xc f gpio/n/0/mode = 0 = 0x0 f gpio/n/1/mode = 75 = 0x4b f gpio/n/2/mode = 0 = 0x0 f gpio/n/3/mode = 0 = 0x0 f gpio/n/4/mode = 0 = 0x0 f gpio/n/5/mode = 0 = 0x0 f gpio/n/6/mode = 0 = 0x0 f gpio/n/7/mode = 0 = 0x0 f gpio/n/11/mode = 75 = 0x4b f gpio/n/12/mode = 75 = 0x4b f gpio/n/18/mode = 0 = 0x0 f gpio/n/29/mode = 0 = 0x0 f gpio/n/30/mode = 0 = 0x0 f gpio/n/31/mode = 0 = 0x0 f gpio/n/45/mode = 0 = 0x0 f wifi/ant = 1 = 0x1 f wifi/enable = 1 = 0x1 f wifi/profile/10/security = 40 = 0x28 f wifi/profile/10/key = "" f wifi/profile/10/enable = 1 = 0x1 f sys/mfg_mode = 0 = 0x0 f client/enable = 1 = 0x1 f log/mod/13/mask = 15 = 0xf f eth/enable = 0 = 0x0 f eth/mac_addr = len 6 00 00 00 00 00 00 f eth/speed = 0 = 0x0 f wifi/power = 31 = 0x1f f wifi/setup_ios_app = "iMDA" f wifi/setup_mode/enable = 0 = 0x0 f wifi/setup_mode/key = (set) f wifi/setup_mode/id = "" f wifi/profile/10/ssid = "Ayla-DevKit" f sys/setup_mode = 0 = 0x0 f sys/setup_mode/key = len 20 f3 13 33 ff 94 79 2c 30 f6 c7 77 f client/server/region = "" f oem/oem = "0dfc7900" f oem/model = "AylaShield" f oem/key = len 256 bf 76 c7 16 cb 31 50 8d 7e 17 3c f oem/version = "demo_dp 1.7" f server/security/enable = 1 = 0x1 f gpio/status/reg = 20 = 0x14 f gpio/status/WPS = 0 = 0x0 f gpio/status/snapshot = 0 = 0x0 f gpio/status/clock = 0 = 0x0 f gpio/status/data = 0 = 0x0 f gpio/status/reset = 0 = 0x0 f gpio/status/test = 0 = 0x0 f gpio/status/ap_mode/setup_mode = 0 = 0x0 f gpio/n/15/mode = 81 = 0x51 f gpio/n/19/mode = 0 = 0x0 f gpio/n/20/mode = 81 = 0x51 s client/user/hostname = "Ayla Dev Kit" s sys/reset = 0 = 0x0 s wifi/scan/profile = len 78 02 06 09 54 68 6f 72 6e 64 69 6b s wifi/profile/0/ssid = "Thorndike" s wifi/profile/0/security = 43 = 0x2b s wifi/profile/0/key = (set) s wifi/profile/0/enable = 1 = 0x1 s sys/timezone_valid = 1 = 0x1 s sys/timezone = 300 = 0x12c s sys/dst_active = 1 = 0x1 s sys/dst_change = 1572760800 = 0x5dbe6ce0 s sys/dst_valid = 1 = 0x1 s client/lan/enable = 1 = 0x1 s client/lan/poll_interval = 30 = 0x1e s client/lan/private_key = (set) s client/lan/key = 1722 = 0x6ba s client/lan/auto = 1 = 0x1 s client/reg/ready = 1 = 0x1 types: f = factory, s = startup, r = running
This table compares reset and connected configuration values:
Parameter | Reset Value | Connected Value | Comment |
---|---|---|---|
sys/reset | 1 | 0 | |
sys/timezone_valid | 0 | 1 | |
sys/timezone | 0 | 300 | See Earth Time Zones |
sys/dst_active | 0 | 1 | Daylight Savings Time |
sys/dst_change | 0 | 1572760800 | |
sys/dst_valid | 0 | 1 | |
client/lan/enable | 0 | 1 | |
client/user/hostname | "Ayla Dev Kit" | ||
wifi/scan/profile | len 78 02 06 09 54 68 6f 72 6e 64 69 6b | ||
wifi/profile/0/ssid | "Thorndike" | ||
wifi/profile/0/security | 43 | ||
wifi/profile/0/key | (set) | ||
wifi/profile/0/enable | 1 | ||
client/lan/poll_interval | 30 | ||
client/lan/private_key | (set) | ||
client/lan/key | 1722 | ||
client/lan/auto | 1 | ||
client/reg/ready | 1 |
Updated over 1 year ago